permission-node: wrap request and response arrays in object

Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>
This commit is contained in:
MT Lewis
2022-01-06 12:18:01 +00:00
parent ef291ff985
commit 1fb2e0e0b4
5 changed files with 196 additions and 151 deletions
@@ -39,7 +39,9 @@ describe('PermissionIntegrationClient', () => {
const mockApplyConditionsHandler = jest.fn(
(_req, res, { json }: RestContext) => {
return res(json([{ id: '123', result: AuthorizeResult.ALLOW }]));
return res(
json({ items: [{ id: '123', result: AuthorizeResult.ALLOW }] }),
);
},
);
@@ -101,14 +103,16 @@ describe('PermissionIntegrationClient', () => {
expect(mockApplyConditionsHandler).toHaveBeenCalledWith(
expect.objectContaining({
body: [
{
id: '123',
resourceRef: 'testResource1',
resourceType: 'test-resource',
conditions: mockConditions,
},
],
body: {
items: [
{
id: '123',
resourceRef: 'testResource1',
resourceType: 'test-resource',
conditions: mockConditions,
},
],
},
}),
expect.anything(),
expect.anything(),
@@ -184,7 +188,9 @@ describe('PermissionIntegrationClient', () => {
it('should reject invalid responses', async () => {
mockApplyConditionsHandler.mockImplementationOnce(
(_req, res, { json }: RestContext) => {
return res(json([{ id: '123', outcome: AuthorizeResult.ALLOW }]));
return res(
json({ items: [{ id: '123', outcome: AuthorizeResult.ALLOW }] }),
);
},
);
@@ -204,11 +210,13 @@ describe('PermissionIntegrationClient', () => {
mockApplyConditionsHandler.mockImplementationOnce(
(_req, res, { json }: RestContext) => {
return res(
json([
{ id: '123', result: AuthorizeResult.ALLOW },
{ id: '456', result: AuthorizeResult.DENY },
{ id: '789', result: AuthorizeResult.ALLOW },
]),
json({
items: [
{ id: '123', result: AuthorizeResult.ALLOW },
{ id: '456', result: AuthorizeResult.DENY },
{ id: '789', result: AuthorizeResult.ALLOW },
],
}),
);
},
);
@@ -20,18 +20,20 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { AuthorizeResult } from '@backstage/plugin-permission-common';
import {
ApplyConditionsRequestEntry,
ApplyConditionsResponse,
ApplyConditionsResponseEntry,
ConditionalPolicyDecision,
} from '@backstage/plugin-permission-node';
const responseSchema = z.array(
z.object({
id: z.string(),
result: z
.literal(AuthorizeResult.ALLOW)
.or(z.literal(AuthorizeResult.DENY)),
}),
);
const responseSchema = z.object({
items: z.array(
z.object({
id: z.string(),
result: z
.literal(AuthorizeResult.ALLOW)
.or(z.literal(AuthorizeResult.DENY)),
}),
),
});
export type ResourcePolicyDecision = ConditionalPolicyDecision & {
resourceRef: string;
@@ -48,21 +50,23 @@ export class PermissionIntegrationClient {
pluginId: string,
decisions: readonly ApplyConditionsRequestEntry[],
authHeader?: string,
): Promise<ApplyConditionsResponse> {
): Promise<ApplyConditionsResponseEntry[]> {
const endpoint = `${await this.discovery.getBaseUrl(
pluginId,
)}/.well-known/backstage/permissions/apply-conditions`;
const response = await fetch(endpoint, {
method: 'POST',
body: JSON.stringify(
decisions.map(({ id, resourceRef, resourceType, conditions }) => ({
id,
resourceRef,
resourceType,
conditions,
})),
),
body: JSON.stringify({
items: decisions.map(
({ id, resourceRef, resourceType, conditions }) => ({
id,
resourceRef,
resourceType,
conditions,
}),
),
}),
headers: {
...(authHeader ? { authorization: authHeader } : {}),
'content-type': 'application/json',
@@ -75,6 +79,8 @@ export class PermissionIntegrationClient {
);
}
return responseSchema.parse(await response.json());
const result = responseSchema.parse(await response.json());
return result.items;
}
}