diff --git a/.changeset/big-moles-visit.md b/.changeset/big-moles-visit.md new file mode 100644 index 0000000000..e1af13bc55 --- /dev/null +++ b/.changeset/big-moles-visit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-backend': minor +--- + +**BREAKING**: Wrap batched requests and responses to /authorize in an envelope object. The latest version of the PermissionClient in @backstage/permission-common uses the new format - as long as the permission-backend is consumed using this client, no other changes are necessary. diff --git a/.changeset/chilled-cats-marry.md b/.changeset/chilled-cats-marry.md new file mode 100644 index 0000000000..2a91c2bc99 --- /dev/null +++ b/.changeset/chilled-cats-marry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-common': minor +--- + +**BREAKING**: PermissionClient has been updated to use the new request and response format in the latest version of @backstage/permission-backend. diff --git a/plugins/permission-backend/src/service/router.test.ts b/plugins/permission-backend/src/service/router.test.ts index 971cb6a223..fd09cca828 100644 --- a/plugins/permission-backend/src/service/router.test.ts +++ b/plugins/permission-backend/src/service/router.test.ts @@ -103,22 +103,24 @@ describe('createRouter', () => { it('calls the permission policy', async () => { const response = await request(app) .post('/authorize') - .send([ - { - id: '123', - permission: { - name: 'test.permission1', - attributes: {}, + .send({ + items: [ + { + id: '123', + permission: { + name: 'test.permission1', + attributes: {}, + }, }, - }, - { - id: '234', - permission: { - name: 'test.permission2', - attributes: {}, + { + id: '234', + permission: { + name: 'test.permission2', + attributes: {}, + }, }, - }, - ]); + ], + }); expect(response.status).toEqual(200); @@ -141,10 +143,12 @@ describe('createRouter', () => { undefined, ); - expect(response.body).toEqual([ - { id: '123', result: AuthorizeResult.DENY }, - { id: '234', result: AuthorizeResult.DENY }, - ]); + expect(response.body).toEqual({ + items: [ + { id: '123', result: AuthorizeResult.DENY }, + { id: '234', result: AuthorizeResult.DENY }, + ], + }); }); it('resolves identity from the Authorization header', async () => { @@ -152,15 +156,17 @@ describe('createRouter', () => { const response = await request(app) .post('/authorize') .auth(token, { type: 'bearer' }) - .send([ - { - id: '123', - permission: { - name: 'test.permission', - attributes: {}, + .send({ + items: [ + { + id: '123', + permission: { + name: 'test.permission', + attributes: {}, + }, }, - }, - ]); + ], + }); expect(response.status).toEqual(200); expect(policy.handle).toHaveBeenCalledWith( @@ -172,9 +178,9 @@ describe('createRouter', () => { }, { id: 'test-user', token: 'test-token' }, ); - expect(response.body).toEqual([ - { id: '123', result: AuthorizeResult.ALLOW }, - ]); + expect(response.body).toEqual({ + items: [{ id: '123', result: AuthorizeResult.ALLOW }], + }); }); describe('conditional policy result', () => { @@ -188,27 +194,31 @@ describe('createRouter', () => { const response = await request(app) .post('/authorize') - .send([ - { - id: '123', - permission: { - name: 'test.permission', - resourceType: 'test-resource-1', - attributes: {}, + .send({ + items: [ + { + id: '123', + permission: { + name: 'test.permission', + resourceType: 'test-resource-1', + attributes: {}, + }, }, - }, - ]); + ], + }); expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { - id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'test-plugin', - resourceType: 'test-resource-1', - conditions: { rule: 'test-rule', params: ['abc'] }, - }, - ]); + expect(response.body).toEqual({ + items: [ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'test-plugin', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['abc'] }, + }, + ], + }); }); it('makes separate batched requests to multiple plugin backends', async () => { @@ -241,44 +251,46 @@ describe('createRouter', () => { const response = await request(app) .post('/authorize') .auth('test-token', { type: 'bearer' }) - .send([ - { - id: '123', - permission: { - name: 'test.permission.1', - resourceType: 'test-resource-1', - attributes: {}, + .send({ + items: [ + { + id: '123', + permission: { + name: 'test.permission.1', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:1', }, - resourceRef: 'resource:1', - }, - { - id: '234', - permission: { - name: 'test.permission.2', - resourceType: 'test-resource-2', - attributes: {}, + { + id: '234', + permission: { + name: 'test.permission.2', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:2', }, - resourceRef: 'resource:2', - }, - { - id: '345', - permission: { - name: 'test.permission.3', - resourceType: 'test-resource-1', - attributes: {}, + { + id: '345', + permission: { + name: 'test.permission.3', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:3', }, - resourceRef: 'resource:3', - }, - { - id: '456', - permission: { - name: 'test.permission.4', - resourceType: 'test-resource-2', - attributes: {}, + { + id: '456', + permission: { + name: 'test.permission.4', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:4', }, - resourceRef: 'resource:4', - }, - ]); + ], + }); expect(mockApplyConditions).toHaveBeenCalledWith( 'plugin-1', @@ -319,12 +331,14 @@ describe('createRouter', () => { ); expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { id: '123', result: AuthorizeResult.ALLOW }, - { id: '234', result: AuthorizeResult.ALLOW }, - { id: '345', result: AuthorizeResult.DENY }, - { id: '456', result: AuthorizeResult.DENY }, - ]); + expect(response.body).toEqual({ + items: [ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.ALLOW }, + { id: '345', result: AuthorizeResult.DENY }, + { id: '456', result: AuthorizeResult.DENY }, + ], + }); }); it('leaves definitive results unchanged', async () => { @@ -363,60 +377,62 @@ describe('createRouter', () => { const response = await request(app) .post('/authorize') .auth('test-token', { type: 'bearer' }) - .send([ - { - id: '123', - permission: { - name: 'test.permission.1', - resourceType: 'test-resource-1', - attributes: {}, + .send({ + items: [ + { + id: '123', + permission: { + name: 'test.permission.1', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:1', }, - resourceRef: 'resource:1', - }, - { - id: '234', - permission: { - name: 'test.permission.2', - resourceType: 'test-resource-2', - attributes: {}, + { + id: '234', + permission: { + name: 'test.permission.2', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:2', }, - resourceRef: 'resource:2', - }, - { - id: '345', - permission: { - name: 'test.permission.3', - resourceType: 'test-resource-1', - attributes: {}, + { + id: '345', + permission: { + name: 'test.permission.3', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:3', }, - resourceRef: 'resource:3', - }, - { - id: '456', - permission: { - name: 'test.permission.4', - resourceType: 'test-resource-1', - attributes: {}, + { + id: '456', + permission: { + name: 'test.permission.4', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:4', }, - resourceRef: 'resource:4', - }, - { - id: '567', - permission: { - name: 'test.permission.5', - resourceType: 'test-resource-2', - attributes: {}, + { + id: '567', + permission: { + name: 'test.permission.5', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:5', }, - resourceRef: 'resource:5', - }, - { - id: '678', - permission: { - name: 'test.permission.6', - attributes: {}, + { + id: '678', + permission: { + name: 'test.permission.6', + attributes: {}, + }, }, - }, - ]); + ], + }); expect(mockApplyConditions).toHaveBeenCalledWith( 'plugin-1', @@ -457,14 +473,16 @@ describe('createRouter', () => { ); expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { id: '123', result: AuthorizeResult.DENY }, - { id: '234', result: AuthorizeResult.DENY }, - { id: '345', result: AuthorizeResult.ALLOW }, - { id: '456', result: AuthorizeResult.ALLOW }, - { id: '567', result: AuthorizeResult.ALLOW }, - { id: '678', result: AuthorizeResult.DENY }, - ]); + expect(response.body).toEqual({ + items: [ + { id: '123', result: AuthorizeResult.DENY }, + { id: '234', result: AuthorizeResult.DENY }, + { id: '345', result: AuthorizeResult.ALLOW }, + { id: '456', result: AuthorizeResult.ALLOW }, + { id: '567', result: AuthorizeResult.ALLOW }, + { id: '678', result: AuthorizeResult.DENY }, + ], + }); }); it('leaves conditional results without resourceRefs unchanged', async () => { @@ -494,43 +512,45 @@ describe('createRouter', () => { const response = await request(app) .post('/authorize') .auth('test-token', { type: 'bearer' }) - .send([ - { - id: '123', - permission: { - name: 'test.permission.1', - resourceType: 'test-resource-1', - attributes: {}, + .send({ + items: [ + { + id: '123', + permission: { + name: 'test.permission.1', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:1', }, - resourceRef: 'resource:1', - }, - { - id: '234', - permission: { - name: 'test.permission.2', - resourceType: 'test-resource-2', - attributes: {}, + { + id: '234', + permission: { + name: 'test.permission.2', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:2', }, - resourceRef: 'resource:2', - }, - { - id: '345', - permission: { - name: 'test.permission.3', - resourceType: 'test-resource-1', - attributes: {}, + { + id: '345', + permission: { + name: 'test.permission.3', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:3', }, - resourceRef: 'resource:3', - }, - { - id: '456', - permission: { - name: 'test.permission.4', - resourceType: 'test-resource-1', - attributes: {}, + { + id: '456', + permission: { + name: 'test.permission.4', + resourceType: 'test-resource-1', + attributes: {}, + }, }, - }, - ]); + ], + }); expect(mockApplyConditions).toHaveBeenCalledWith( 'plugin-1', @@ -559,18 +579,20 @@ describe('createRouter', () => { ); expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { id: '123', result: AuthorizeResult.ALLOW }, - { id: '234', result: AuthorizeResult.ALLOW }, - { id: '345', result: AuthorizeResult.ALLOW }, - { - id: '456', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', - resourceType: 'test-resource-1', - conditions: { rule: 'test-rule', params: ['abc'] }, - }, - ]); + expect(response.body).toEqual({ + items: [ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.ALLOW }, + { id: '345', result: AuthorizeResult.ALLOW }, + { + id: '456', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['abc'] }, + }, + ], + }); }); it.each<[ApplyConditionsResponseEntry['result'], string]>([ @@ -600,26 +622,28 @@ describe('createRouter', () => { const response = await request(app) .post('/authorize') .auth('test-token', { type: 'bearer' }) - .send([ - { - id: '123', - resourceRef: 'test/resource', - permission: { - name: 'test.permission', - resourceType: 'test-resource-1', - attributes: {}, + .send({ + items: [ + { + id: '123', + resourceRef: 'test/resource', + permission: { + name: 'test.permission', + resourceType: 'test-resource-1', + attributes: {}, + }, }, - }, - { - id: '234', - resourceRef: 'test/resource', - permission: { - name: 'test.permission', - resourceType: 'test-resource-1', - attributes: {}, + { + id: '234', + resourceRef: 'test/resource', + permission: { + name: 'test.permission', + resourceType: 'test-resource-1', + attributes: {}, + }, }, - }, - ]); + ], + }); expect(mockApplyConditions).toHaveBeenCalledWith( 'test-plugin', @@ -641,16 +665,18 @@ describe('createRouter', () => { ); expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { - id: '123', - result, - }, - { - id: '234', - result, - }, - ]); + expect(response.body).toEqual({ + items: [ + { + id: '123', + result, + }, + { + id: '234', + result, + }, + ], + }); }, ); }); @@ -660,9 +686,14 @@ describe('createRouter', () => { '', {}, [{ permission: { name: 'test.permission', attributes: {} } }], - [{ id: '123' }], - [{ id: '123', permission: { name: 'test.permission' } }], - [{ id: '123', permission: { attributes: { invalid: 'attribute' } } }], + { items: [{ permission: { name: 'test.permission', attributes: {} } }] }, + { items: [{ id: '123' }] }, + { items: [{ id: '123', permission: { name: 'test.permission' } }] }, + { + items: [ + { id: '123', permission: { attributes: { invalid: 'attribute' } } }, + ], + }, ])('returns a 400 error for invalid request %#', async requestBody => { const response = await request(app).post('/authorize').send(requestBody); @@ -686,16 +717,18 @@ describe('createRouter', () => { const response = await request(app) .post('/authorize') - .send([ - { - id: '123', - permission: { - name: 'test.permission', - resourceType: 'test-resource-1', - attributes: {}, + .send({ + items: [ + { + id: '123', + permission: { + name: 'test.permission', + resourceType: 'test-resource-1', + attributes: {}, + }, }, - }, - ]); + ], + }); expect(response.status).toEqual(500); expect(response.body).toEqual( diff --git a/plugins/permission-backend/src/service/router.ts b/plugins/permission-backend/src/service/router.ts index 58438afbb5..c504fdbe3a 100644 --- a/plugins/permission-backend/src/service/router.ts +++ b/plugins/permission-backend/src/service/router.ts @@ -32,6 +32,8 @@ import { AuthorizeResponse, AuthorizeRequest, Identified, + AuthorizeRequestEnvelope, + AuthorizeResponseEnvelope, } from '@backstage/plugin-permission-common'; import { ApplyConditionsRequestEntry, @@ -42,26 +44,28 @@ import { PermissionIntegrationClient } from './PermissionIntegrationClient'; import { memoize } from 'lodash'; import DataLoader from 'dataloader'; -const requestSchema: z.ZodSchema[]> = z.array( - z.object({ - id: z.string(), - resourceRef: z.string().optional(), - permission: z.object({ - name: z.string(), - resourceType: z.string().optional(), - attributes: z.object({ - action: z - .union([ - z.literal('create'), - z.literal('read'), - z.literal('update'), - z.literal('delete'), - ]) - .optional(), +const requestSchema: z.ZodSchema = z.object({ + items: z.array( + z.object({ + id: z.string(), + resourceRef: z.string().optional(), + permission: z.object({ + name: z.string(), + resourceType: z.string().optional(), + attributes: z.object({ + action: z + .union([ + z.literal('create'), + z.literal('read'), + z.literal('update'), + z.literal('delete'), + ]) + .optional(), + }), }), }), - }), -); + ), +}); /** * Options required when constructing a new {@link express#Router} using @@ -150,8 +154,8 @@ export async function createRouter( router.post( '/authorize', async ( - req: Request[]>, - res: Response[]>, + req: Request, + res: Response, ) => { const token = IdentityClient.getBearerToken(req.header('authorization')); const user = token ? await identity.authenticate(token) : undefined; @@ -164,15 +168,15 @@ export async function createRouter( const body = parseResult.data; - res.json( - await handleRequest( - body, + res.json({ + items: await handleRequest( + body.items, user, policy, permissionIntegrationClient, req.header('authorization'), ), - ); + }); }, ); diff --git a/plugins/permission-common/api-report.md b/plugins/permission-common/api-report.md index 70795d14ac..3c681cc46f 100644 --- a/plugins/permission-common/api-report.md +++ b/plugins/permission-common/api-report.md @@ -11,6 +11,11 @@ export type AuthorizeRequest = { resourceRef?: string; }; +// @public +export type AuthorizeRequestEnvelope = { + items: Identified[]; +}; + // @public export type AuthorizeRequestOptions = { token?: string; @@ -26,6 +31,11 @@ export type AuthorizeResponse = conditions: PermissionCriteria; }; +// @public +export type AuthorizeResponseEnvelope = { + items: Identified[]; +}; + // @public export enum AuthorizeResult { ALLOW = 'ALLOW', diff --git a/plugins/permission-common/src/PermissionClient.test.ts b/plugins/permission-common/src/PermissionClient.test.ts index a432735a5e..0cd6a09af9 100644 --- a/plugins/permission-common/src/PermissionClient.test.ts +++ b/plugins/permission-common/src/PermissionClient.test.ts @@ -54,12 +54,14 @@ describe('PermissionClient', () => { describe('authorize', () => { const mockAuthorizeHandler = jest.fn((req, res, { json }: RestContext) => { - const responses = req.body.map((a: Identified) => ({ - id: a.id, - result: AuthorizeResult.ALLOW, - })); + const responses = req.body.items.map( + (a: Identified) => ({ + id: a.id, + result: AuthorizeResult.ALLOW, + }), + ); - return res(json(responses)); + return res(json({ items: responses })); }); beforeEach(() => { @@ -79,12 +81,15 @@ describe('PermissionClient', () => { await client.authorize([mockAuthorizeRequest]); const request = mockAuthorizeHandler.mock.calls[0][0]; - expect(request.body[0]).toEqual( - expect.objectContaining({ - permission: mockPermission, - resourceRef: 'foo', - }), - ); + + expect(request.body).toEqual({ + items: [ + expect.objectContaining({ + permission: mockPermission, + resourceRef: 'foo', + }), + ], + }); }); it('should return the response from the fetch request', async () => { @@ -122,7 +127,11 @@ describe('PermissionClient', () => { it('should reject responses with missing ids', async () => { mockAuthorizeHandler.mockImplementationOnce( (_req, res, { json }: RestContext) => { - return res(json([{ id: 'wrong-id', result: AuthorizeResult.ALLOW }])); + return res( + json({ + items: [{ id: 'wrong-id', result: AuthorizeResult.ALLOW }], + }), + ); }, ); await expect( @@ -133,12 +142,14 @@ describe('PermissionClient', () => { it('should reject invalid responses', async () => { mockAuthorizeHandler.mockImplementationOnce( (req, res, { json }: RestContext) => { - const responses = req.body.map((a: Identified) => ({ - id: a.id, - outcome: AuthorizeResult.ALLOW, - })); + const responses = req.body.items.map( + (a: Identified) => ({ + id: a.id, + outcome: AuthorizeResult.ALLOW, + }), + ); - return res(json(responses)); + return res(json({ items: responses })); }, ); await expect( @@ -151,10 +162,10 @@ describe('PermissionClient', () => { (req, res, { json }: RestContext) => { const responses = req.body.map((a: Identified) => ({ id: a.id, - outcome: AuthorizeResult.DENY, + result: AuthorizeResult.DENY, })); - return res(json(responses)); + return res(json({ items: responses })); }, ); const disabled = new PermissionClient({ diff --git a/plugins/permission-common/src/PermissionClient.ts b/plugins/permission-common/src/PermissionClient.ts index 62e5ec8172..6e45bdc072 100644 --- a/plugins/permission-common/src/PermissionClient.ts +++ b/plugins/permission-common/src/PermissionClient.ts @@ -26,6 +26,8 @@ import { Identified, PermissionCriteria, PermissionCondition, + AuthorizeResponseEnvelope, + AuthorizeRequestEnvelope, } from './types/api'; import { DiscoveryApi } from './types/discovery'; import { @@ -46,22 +48,24 @@ const permissionCriteriaSchema: z.ZodSchema< .or(z.object({ not: permissionCriteriaSchema })), ); -const responseSchema = z.array( - z - .object({ - id: z.string(), - result: z - .literal(AuthorizeResult.ALLOW) - .or(z.literal(AuthorizeResult.DENY)), - }) - .or( - z.object({ +const responseSchema = z.object({ + items: z.array( + z + .object({ id: z.string(), - result: z.literal(AuthorizeResult.CONDITIONAL), - conditions: permissionCriteriaSchema, - }), - ), -); + result: z + .literal(AuthorizeResult.ALLOW) + .or(z.literal(AuthorizeResult.DENY)), + }) + .or( + z.object({ + id: z.string(), + result: z.literal(AuthorizeResult.CONDITIONAL), + conditions: permissionCriteriaSchema, + }), + ), + ), +}); /** * An isomorphic client for requesting authorization for Backstage permissions. @@ -106,17 +110,17 @@ export class PermissionClient implements PermissionAuthorizer { return requests.map(_ => ({ result: AuthorizeResult.ALLOW })); } - const identifiedRequests: Identified[] = requests.map( - request => ({ + const requestEnvelope: AuthorizeRequestEnvelope = { + items: requests.map(request => ({ id: uuid.v4(), ...request, - }), - ); + })), + }; const permissionApi = await this.discovery.getBaseUrl('permission'); const response = await fetch(`${permissionApi}/authorize`, { method: 'POST', - body: JSON.stringify(identifiedRequests), + body: JSON.stringify(requestEnvelope), headers: { ...this.getAuthorizationHeader(options?.token), 'content-type': 'application/json', @@ -126,15 +130,15 @@ export class PermissionClient implements PermissionAuthorizer { throw await ResponseError.fromResponse(response); } - const identifiedResponses = await response.json(); - this.assertValidResponses(identifiedRequests, identifiedResponses); + const responseEnvelope = await response.json(); + this.assertValidResponses(requestEnvelope, responseEnvelope); - const responsesById = identifiedResponses.reduce((acc, r) => { + const responsesById = responseEnvelope.items.reduce((acc, r) => { acc[r.id] = r; return acc; }, {} as Record>); - return identifiedRequests.map(request => responsesById[request.id]); + return requestEnvelope.items.map(request => responsesById[request.id]); } private getAuthorizationHeader(token?: string): Record { @@ -142,12 +146,14 @@ export class PermissionClient implements PermissionAuthorizer { } private assertValidResponses( - requests: Identified[], + requestEnvelope: AuthorizeRequestEnvelope, json: any, - ): asserts json is Identified[] { + ): asserts json is AuthorizeResponseEnvelope { const authorizedResponses = responseSchema.parse(json); - const responseIds = authorizedResponses.map(r => r.id); - const hasAllRequestIds = requests.every(r => responseIds.includes(r.id)); + const responseIds = authorizedResponses.items.map(r => r.id); + const hasAllRequestIds = requestEnvelope.items.every(r => + responseIds.includes(r.id), + ); if (!hasAllRequestIds) { throw new Error( 'Unexpected authorization response from permission-backend', diff --git a/plugins/permission-common/src/types/api.ts b/plugins/permission-common/src/types/api.ts index 7f4cd0730b..abdae021d0 100644 --- a/plugins/permission-common/src/types/api.ts +++ b/plugins/permission-common/src/types/api.ts @@ -43,7 +43,7 @@ export enum AuthorizeResult { } /** - * An authorization request for {@link PermissionClient#authorize}. + * An individual authorization request for {@link PermissionClient#authorize}. * @public */ export type AuthorizeRequest = { @@ -51,6 +51,14 @@ export type AuthorizeRequest = { resourceRef?: string; }; +/** + * A batch of authorization requests from {@link PermissionClient#authorize}. + * @public + */ +export type AuthorizeRequestEnvelope = { + items: Identified[]; +}; + /** * A condition returned with a CONDITIONAL authorization response. * @@ -75,7 +83,7 @@ export type PermissionCriteria = | TQuery; /** - * An authorization response from {@link PermissionClient#authorize}. + * An individual authorization response from {@link PermissionClient#authorize}. * @public */ export type AuthorizeResponse = @@ -84,3 +92,11 @@ export type AuthorizeResponse = result: AuthorizeResult.CONDITIONAL; conditions: PermissionCriteria; }; + +/** + * A batch of authorization responses from {@link PermissionClient#authorize}. + * @public + */ +export type AuthorizeResponseEnvelope = { + items: Identified[]; +}; diff --git a/plugins/permission-common/src/types/index.ts b/plugins/permission-common/src/types/index.ts index 583a3577bd..9fbe911941 100644 --- a/plugins/permission-common/src/types/index.ts +++ b/plugins/permission-common/src/types/index.ts @@ -17,7 +17,9 @@ export { AuthorizeResult } from './api'; export type { AuthorizeRequest, + AuthorizeRequestEnvelope, AuthorizeResponse, + AuthorizeResponseEnvelope, Identified, PermissionCondition, PermissionCriteria, diff --git a/plugins/permission-node/src/ServerPermissionClient.test.ts b/plugins/permission-node/src/ServerPermissionClient.test.ts index 2c29ef8939..4864aa4606 100644 --- a/plugins/permission-node/src/ServerPermissionClient.test.ts +++ b/plugins/permission-node/src/ServerPermissionClient.test.ts @@ -32,12 +32,12 @@ import { RestContext, rest } from 'msw'; const server = setupServer(); const mockAuthorizeHandler = jest.fn((req, res, { json }: RestContext) => { - const responses = req.body.map((r: Identified) => ({ + const responses = req.body.items.map((r: Identified) => ({ id: r.id, result: AuthorizeResult.ALLOW, })); - return res(json(responses)); + return res(json({ items: responses })); }); const mockBaseUrl = 'http://backstage:9191/i-am-a-mock-base'; const discovery: PluginEndpointDiscovery = {