docs: add permissions documentation for actions registry
Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
@@ -3,3 +3,28 @@
|
||||
---
|
||||
|
||||
Added optional `permission` field to `ActionsRegistryActionOptions`, allowing actions to declare a `BasicPermission` that controls visibility and access.
|
||||
|
||||
```typescript
|
||||
import { createPermission } from '@backstage/plugin-permission-common';
|
||||
|
||||
const myPermission = createPermission({
|
||||
name: 'myPlugin.myAction.use',
|
||||
attributes: {},
|
||||
});
|
||||
|
||||
actionsRegistry.register({
|
||||
name: 'my-action',
|
||||
title: 'My Action',
|
||||
description: 'An action that requires permission',
|
||||
permission: myPermission,
|
||||
schema: {
|
||||
input: z => z.object({ name: z.string() }),
|
||||
output: z => z.object({ ok: z.boolean() }),
|
||||
},
|
||||
action: async ({ input }) => {
|
||||
return { output: { ok: true } };
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Actions without a `permission` field continue to work as before.
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
'@backstage/backend-defaults': patch
|
||||
---
|
||||
|
||||
Added permissions integration to the actions registry. Actions with a `permission` field are now checked against the permissions framework when listing and invoking. Denied actions are filtered from listings and return 404 on invocation.
|
||||
Added permissions integration to the actions registry. Actions registered with a `permission` field are now checked against the permissions framework when listing and invoking. Denied actions are filtered from list results, and invoking a denied action returns a `404 Not Found` as if the action does not exist.
|
||||
|
||||
@@ -25,6 +25,7 @@ Each action registered with the service must conform to the `ActionsRegistryActi
|
||||
|
||||
### Optional Properties
|
||||
|
||||
- **`permission`:** A `BasicPermission` that controls visibility and access to the action through the permissions framework. See [Permissions](#permissions) below.
|
||||
- **`attributes`:** Object containing behavioral flags:
|
||||
- **`destructive`:** Boolean indicating if the action modifies or deletes data
|
||||
- **`idempotent`:** Boolean indicating if running the action multiple times produces the same result
|
||||
@@ -157,6 +158,41 @@ export const myPlugin = createBackendPlugin({
|
||||
});
|
||||
```
|
||||
|
||||
## Permissions
|
||||
|
||||
Actions can optionally declare a `permission` to control visibility and access through the Backstage permissions framework. When a permission is set, the action is only visible in listings and accessible by users who are authorized.
|
||||
|
||||
Actions that are denied by the permission policy are filtered from `list()` results and return a `404 Not Found` on `invoke()`, as if they don't exist.
|
||||
|
||||
### Adding a Permission to an Action
|
||||
|
||||
```typescript
|
||||
import { createPermission } from '@backstage/plugin-permission-common';
|
||||
|
||||
// Define a permission for your action
|
||||
const deleteEntityPermission = createPermission({
|
||||
name: 'catalog.entity.delete',
|
||||
attributes: { action: 'delete' },
|
||||
});
|
||||
|
||||
actionsRegistry.register({
|
||||
name: 'delete-entity',
|
||||
title: 'Delete Entity',
|
||||
description: 'Removes an entity from the catalog',
|
||||
permission: deleteEntityPermission,
|
||||
schema: {
|
||||
input: z => z.object({ entityRef: z.string() }),
|
||||
output: z => z.object({ deleted: z.boolean() }),
|
||||
},
|
||||
action: async ({ input }) => {
|
||||
// action logic
|
||||
return { output: { deleted: true } };
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Actions without a `permission` field remain visible and accessible by all callers, preserving backwards compatibility.
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
@@ -65,6 +65,10 @@ backend:
|
||||
- 'scaffolder.internal.*'
|
||||
```
|
||||
|
||||
### Permissions
|
||||
|
||||
Actions registered with a `permission` field are automatically checked against the permissions framework. When listing actions, any actions denied by the active permission policy are filtered out of the results. When invoking a denied action, a `404 Not Found` error is returned. See the [Actions Registry Permissions](./actions-registry.md#permissions) documentation for how to configure permissions on actions.
|
||||
|
||||
## Using the Service
|
||||
|
||||
### Listing Available Actions
|
||||
|
||||
+6
-3
@@ -16,6 +16,7 @@
|
||||
|
||||
import {
|
||||
AuthService,
|
||||
BackstageCredentials,
|
||||
HttpAuthService,
|
||||
LoggerService,
|
||||
PermissionsService,
|
||||
@@ -32,6 +33,8 @@ import {
|
||||
import { InputError, NotAllowedError, NotFoundError } from '@backstage/errors';
|
||||
import { AuthorizeResult } from '@backstage/plugin-permission-common';
|
||||
|
||||
type ActionEntry = [string, ActionsRegistryActionOptions<any, any>];
|
||||
|
||||
export class DefaultActionsRegistryService implements ActionsRegistryService {
|
||||
private actions: Map<string, ActionsRegistryActionOptions<any, any>> =
|
||||
new Map();
|
||||
@@ -196,9 +199,9 @@ export class DefaultActionsRegistryService implements ActionsRegistryService {
|
||||
}
|
||||
|
||||
private async filterByPermissions(
|
||||
entries: [string, ActionsRegistryActionOptions<any, any>][],
|
||||
credentials: Parameters<PermissionsService['authorize']>[1]['credentials'],
|
||||
): Promise<[string, ActionsRegistryActionOptions<any, any>][]> {
|
||||
entries: ActionEntry[],
|
||||
credentials: BackstageCredentials,
|
||||
): Promise<ActionEntry[]> {
|
||||
const permissionedEntries = entries.filter(
|
||||
([_, action]) => action.permission,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user