permission-node: allow batch retrieval of resources in /apply-conditions

Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>
This commit is contained in:
MT Lewis
2021-12-20 14:37:45 +00:00
parent b66704db18
commit 706b6c29e9
4 changed files with 30 additions and 15 deletions
@@ -275,7 +275,11 @@ describe('PermissionIntegrationClient', () => {
router.use(
createPermissionIntegrationRouter({
resourceType: 'test-resource',
getResource: async resourceRef => ({ id: resourceRef }),
getResources: async resourceRefs =>
resourceRefs.reduce((acc, ref) => {
acc[ref] = { id: ref };
return acc;
}, {} as Record<string, { id: string }>),
rules: [
{
name: 'RULE_1',
+1 -1
View File
@@ -97,7 +97,7 @@ export const createConditionTransformer: <
export const createPermissionIntegrationRouter: <TResource>(options: {
resourceType: string;
rules: PermissionRule<TResource, any, unknown[]>[];
getResource: (resourceRef: string) => Promise<TResource | undefined>;
getResources: (resourceRefs: string[]) => Promise<Record<string, TResource>>;
}) => express.Router;
// @public
@@ -19,9 +19,14 @@ import express, { Express, Router } from 'express';
import request, { Response } from 'supertest';
import { createPermissionIntegrationRouter } from './createPermissionIntegrationRouter';
const mockGetResource: jest.MockedFunction<
Parameters<typeof createPermissionIntegrationRouter>[0]['getResource']
> = jest.fn(async resourceRef => ({ id: resourceRef }));
const mockGetResources: jest.MockedFunction<
Parameters<typeof createPermissionIntegrationRouter>[0]['getResources']
> = jest.fn(async resourceRefs =>
resourceRefs.reduce(
(acc, resourceRef) => ({ ...acc, [resourceRef]: { id: resourceRef } }),
{},
),
);
const testRule1 = {
name: 'test-rule-1',
@@ -46,7 +51,7 @@ describe('createPermissionIntegrationRouter', () => {
beforeAll(() => {
router = createPermissionIntegrationRouter({
resourceType: 'test-resource',
getResource: mockGetResource,
getResources: mockGetResources,
rules: [testRule1, testRule2],
});
@@ -214,6 +219,15 @@ describe('createPermissionIntegrationRouter', () => {
{ id: '567', result: AuthorizeResult.ALLOW },
]);
});
it('calls getResources for all required resources at once', () => {
expect(mockGetResources).toHaveBeenCalledWith([
'default:test/resource-1',
'default:test/resource-2',
'default:test/resource-3',
'default:test/resource-4',
]);
});
});
it('returns 400 when called with incorrect resource type', async () => {
@@ -237,7 +251,7 @@ describe('createPermissionIntegrationRouter', () => {
});
it('returns 200/DENY when resource is not found', async () => {
mockGetResource.mockReturnValueOnce(Promise.resolve(undefined));
mockGetResources.mockReturnValueOnce(Promise.resolve({}));
const response = await request(app)
.post('/.well-known/backstage/permissions/apply-conditions')
@@ -156,9 +156,9 @@ const applyConditions = <TResource>(
export const createPermissionIntegrationRouter = <TResource>(options: {
resourceType: string;
rules: PermissionRule<TResource, any>[];
getResource: (resourceRef: string) => Promise<TResource | undefined>;
getResources: (resourceRefs: string[]) => Promise<Record<string, TResource>>;
}): express.Router => {
const { resourceType, rules, getResource } = options;
const { resourceType, rules, getResources } = options;
const router = Router();
const getRule = createGetRule(rules);
@@ -188,12 +188,9 @@ export const createPermissionIntegrationRouter = <TResource>(options: {
assertValidResourceTypes(body);
const resources = {} as Record<string, TResource | undefined>;
for (const { resourceRef } of body) {
if (!resources[resourceRef]) {
resources[resourceRef] = await getResource(resourceRef);
}
}
const resources = await getResources(
Array.from(new Set(body.map(({ resourceRef }) => resourceRef))),
);
return res.status(200).json(
body.map(request => ({