feat(scaffolder): Migrate scaffolder to use permissions registry (#33740)
* feat(scaffolder-node): add PermissionResourceRef definitions for scaffolder resource types Signed-off-by: benjdlambert <ben@blam.sh> * feat(scaffolder-backend): migrate to PermissionsRegistryService with fallback Signed-off-by: benjdlambert <ben@blam.sh> * feat(scaffolder-backend): wire permissionsRegistry in ScaffolderPlugin Signed-off-by: benjdlambert <ben@blam.sh> * test(scaffolder-backend): verify permissions metadata endpoint returns all scaffolder permissions Signed-off-by: benjdlambert <ben@blam.sh> * chore: add changesets for scaffolder permissions registry migration Signed-off-by: benjdlambert <ben@blam.sh> * chore: format scaffolder-node alpha exports Signed-off-by: benjdlambert <ben@blam.sh> * fix: correct scaffolder-node changeset to patch for sub-1.0 package Signed-off-by: benjdlambert <ben@blam.sh> * refactor(scaffolder-backend): simplify by removing fallback path and making permissionsRegistry required Signed-off-by: benjdlambert <ben@blam.sh> * chore: update scaffolder-node API report Signed-off-by: benjdlambert <ben@blam.sh> --------- Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
@@ -27,6 +27,12 @@ import { stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils';
|
||||
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { scaffolderAutocompleteExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha';
|
||||
import {
|
||||
scaffolderPermissions,
|
||||
RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,
|
||||
RESOURCE_TYPE_SCAFFOLDER_ACTION,
|
||||
RESOURCE_TYPE_SCAFFOLDER_TASK,
|
||||
} from '@backstage/plugin-scaffolder-common/alpha';
|
||||
|
||||
import { scaffolderPlugin } from './ScaffolderPlugin';
|
||||
|
||||
@@ -1216,6 +1222,32 @@ describe('scaffolderPlugin', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('exposes permissions metadata via the well-known endpoint', async () => {
|
||||
const { server } = await startTestBackend({
|
||||
features: [scaffolderPlugin],
|
||||
});
|
||||
|
||||
const { body, status } = await request(server).get(
|
||||
'/api/scaffolder/.well-known/backstage/permissions/metadata',
|
||||
);
|
||||
|
||||
expect(status).toBe(200);
|
||||
|
||||
const permissionNames = body.permissions.map(
|
||||
(p: { name: string }) => p.name,
|
||||
);
|
||||
for (const permission of scaffolderPermissions) {
|
||||
expect(permissionNames).toContain(permission.name);
|
||||
}
|
||||
|
||||
const ruleResourceTypes = body.rules.map(
|
||||
(r: { resourceType: string }) => r.resourceType,
|
||||
);
|
||||
expect(ruleResourceTypes).toContain(RESOURCE_TYPE_SCAFFOLDER_TEMPLATE);
|
||||
expect(ruleResourceTypes).toContain(RESOURCE_TYPE_SCAFFOLDER_ACTION);
|
||||
expect(ruleResourceTypes).toContain(RESOURCE_TYPE_SCAFFOLDER_TASK);
|
||||
});
|
||||
|
||||
it('supports listing templating extensions', async () => {
|
||||
const { server } = await startTestBackend({
|
||||
features: [scaffolderPlugin],
|
||||
|
||||
@@ -142,6 +142,7 @@ export const scaffolderPlugin = createBackendPlugin({
|
||||
lifecycle: coreServices.rootLifecycle,
|
||||
reader: coreServices.urlReader,
|
||||
permissions: coreServices.permissions,
|
||||
permissionsRegistry: coreServices.permissionsRegistry,
|
||||
database: coreServices.database,
|
||||
auth: coreServices.auth,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
@@ -165,6 +166,7 @@ export const scaffolderPlugin = createBackendPlugin({
|
||||
httpAuth,
|
||||
catalog,
|
||||
permissions,
|
||||
permissionsRegistry,
|
||||
events,
|
||||
auditor,
|
||||
actionsRegistry,
|
||||
@@ -242,6 +244,7 @@ export const scaffolderPlugin = createBackendPlugin({
|
||||
auth,
|
||||
httpAuth,
|
||||
permissions,
|
||||
permissionsRegistry,
|
||||
autocompleteHandlers,
|
||||
additionalWorkspaceProviders,
|
||||
events,
|
||||
|
||||
@@ -204,6 +204,7 @@ const createTestRouter = async (
|
||||
const httpAuth = mockServices.httpAuth();
|
||||
const events = mockServices.events();
|
||||
|
||||
const permissionsRegistry = mockServices.permissionsRegistry.mock();
|
||||
const router = await createRouter({
|
||||
logger,
|
||||
config: new ConfigReader({}),
|
||||
@@ -211,6 +212,7 @@ const createTestRouter = async (
|
||||
catalog,
|
||||
taskBroker,
|
||||
permissions,
|
||||
permissionsRegistry,
|
||||
auth,
|
||||
httpAuth,
|
||||
events,
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
HttpAuthService,
|
||||
LifecycleService,
|
||||
LoggerService,
|
||||
PermissionsRegistryService,
|
||||
PermissionsService,
|
||||
resolveSafeChildPath,
|
||||
SchedulerService,
|
||||
@@ -45,7 +46,6 @@ import {
|
||||
ConditionTransformer,
|
||||
createConditionAuthorizer,
|
||||
createConditionTransformer,
|
||||
createPermissionIntegrationRouter,
|
||||
} from '@backstage/plugin-permission-node';
|
||||
import {
|
||||
TaskSpec,
|
||||
@@ -53,16 +53,13 @@ import {
|
||||
templateEntityV1beta3Validator,
|
||||
} from '@backstage/plugin-scaffolder-common';
|
||||
import {
|
||||
RESOURCE_TYPE_SCAFFOLDER_ACTION,
|
||||
RESOURCE_TYPE_SCAFFOLDER_TASK,
|
||||
RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,
|
||||
scaffolderActionPermissions,
|
||||
scaffolderPermissions,
|
||||
scaffolderTaskPermissions,
|
||||
scaffolderTemplatePermissions,
|
||||
taskCancelPermission,
|
||||
taskCreatePermission,
|
||||
taskReadPermission,
|
||||
templateManagementPermission,
|
||||
templateParameterReadPermission,
|
||||
templateStepReadPermission,
|
||||
} from '@backstage/plugin-scaffolder-common/alpha';
|
||||
@@ -78,6 +75,9 @@ import {
|
||||
AutocompleteHandler,
|
||||
CreatedTemplateFilter,
|
||||
CreatedTemplateGlobal,
|
||||
scaffolderActionPermissionResourceRef,
|
||||
scaffolderTaskPermissionResourceRef,
|
||||
scaffolderTemplatePermissionResourceRef,
|
||||
WorkspaceProvider,
|
||||
} from '@backstage/plugin-scaffolder-node/alpha';
|
||||
import { HumanDuration, JsonObject } from '@backstage/types';
|
||||
@@ -161,6 +161,7 @@ export interface RouterOptions {
|
||||
| CreatedTemplateGlobal[];
|
||||
additionalWorkspaceProviders?: Record<string, WorkspaceProvider>;
|
||||
permissions?: PermissionsService;
|
||||
permissionsRegistry: PermissionsRegistryService;
|
||||
permissionRules?: Array<ScaffolderPermissionRuleInput>;
|
||||
auth: AuthService;
|
||||
httpAuth: HttpAuthService;
|
||||
@@ -253,6 +254,7 @@ export async function createRouter(
|
||||
additionalTemplateGlobals,
|
||||
additionalWorkspaceProviders,
|
||||
permissions,
|
||||
permissionsRegistry,
|
||||
permissionRules,
|
||||
autocompleteHandlers = {},
|
||||
events: eventsService,
|
||||
@@ -410,35 +412,35 @@ export async function createRouter(
|
||||
const taskTransformConditions: ConditionTransformer<TaskFilters> =
|
||||
createConditionTransformer(Object.values(taskRules));
|
||||
|
||||
const permissionIntegrationRouter = createPermissionIntegrationRouter({
|
||||
resources: [
|
||||
{
|
||||
resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,
|
||||
permissions: scaffolderTemplatePermissions,
|
||||
rules: templateRules,
|
||||
},
|
||||
{
|
||||
resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,
|
||||
permissions: scaffolderActionPermissions,
|
||||
rules: actionRules,
|
||||
},
|
||||
{
|
||||
resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK,
|
||||
permissions: scaffolderTaskPermissions,
|
||||
rules: taskRules,
|
||||
getResources: async resourceRefs => {
|
||||
return Promise.all(
|
||||
resourceRefs.map(async taskId => {
|
||||
return await taskBroker.get(taskId);
|
||||
}),
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
permissions: scaffolderPermissions,
|
||||
permissionsRegistry.addResourceType({
|
||||
resourceRef: scaffolderTemplatePermissionResourceRef,
|
||||
permissions: scaffolderTemplatePermissions,
|
||||
rules: templateRules,
|
||||
});
|
||||
|
||||
router.use(permissionIntegrationRouter);
|
||||
permissionsRegistry.addResourceType({
|
||||
resourceRef: scaffolderActionPermissionResourceRef,
|
||||
permissions: scaffolderActionPermissions,
|
||||
rules: actionRules,
|
||||
});
|
||||
|
||||
permissionsRegistry.addResourceType({
|
||||
resourceRef: scaffolderTaskPermissionResourceRef,
|
||||
permissions: scaffolderTaskPermissions,
|
||||
rules: taskRules,
|
||||
getResources: async resourceRefs => {
|
||||
return Promise.all(
|
||||
resourceRefs.map(async taskId => {
|
||||
return await taskBroker.get(taskId);
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
permissionsRegistry.addPermissions([
|
||||
taskCreatePermission,
|
||||
templateManagementPermission,
|
||||
]);
|
||||
|
||||
router
|
||||
.get(
|
||||
|
||||
Reference in New Issue
Block a user