Add permission-common package
Signed-off-by: Tim Hansen <timbonicus@gmail.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
# @backstage/permission-common
|
||||
|
||||
> NOTE: THIS PACKAGE IS EXPERIMENTAL, HERE BE DRAGONS
|
||||
|
||||
Isomorphic types and client for Backstage permissions and authorization. For
|
||||
more information, see the [authorization
|
||||
PRFC](https://github.com/backstage/backstage/pull/7761).
|
||||
@@ -0,0 +1,116 @@
|
||||
## API Report File for "@backstage/permission-common"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
// @public
|
||||
export type AuthorizeRequest = {
|
||||
permission: Permission;
|
||||
resourceRef?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type AuthorizeRequestOptions = {
|
||||
token?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type AuthorizeResponse =
|
||||
| {
|
||||
result: AuthorizeResult.ALLOW | AuthorizeResult.DENY;
|
||||
}
|
||||
| {
|
||||
result: AuthorizeResult.CONDITIONAL;
|
||||
conditions: PermissionCriteria;
|
||||
};
|
||||
|
||||
// @public
|
||||
export enum AuthorizeResult {
|
||||
ALLOW = 'ALLOW',
|
||||
CONDITIONAL = 'CONDITIONAL',
|
||||
DENY = 'DENY',
|
||||
}
|
||||
|
||||
// @public
|
||||
export type DiscoveryApi = {
|
||||
getBaseUrl(pluginId: string): Promise<string>;
|
||||
};
|
||||
|
||||
// @public
|
||||
export class Permission {
|
||||
constructor(
|
||||
name: string,
|
||||
attributes: PermissionAttributes,
|
||||
resourceType?: string | undefined,
|
||||
);
|
||||
// (undocumented)
|
||||
readonly attributes: PermissionAttributes;
|
||||
// (undocumented)
|
||||
static create({ name, attributes, resourceType }: PermissionJSON): Permission;
|
||||
// (undocumented)
|
||||
is(permission: Permission): boolean;
|
||||
// (undocumented)
|
||||
get isCreate(): boolean;
|
||||
// (undocumented)
|
||||
get isDelete(): boolean;
|
||||
// (undocumented)
|
||||
get isRead(): boolean;
|
||||
// (undocumented)
|
||||
get isUpdate(): boolean;
|
||||
// (undocumented)
|
||||
readonly name: string;
|
||||
// (undocumented)
|
||||
readonly resourceType?: string | undefined;
|
||||
// (undocumented)
|
||||
toJSON(): PermissionJSON;
|
||||
}
|
||||
|
||||
// @public
|
||||
export enum PermissionAction {
|
||||
// (undocumented)
|
||||
Create = 'create',
|
||||
// (undocumented)
|
||||
Delete = 'delete',
|
||||
// (undocumented)
|
||||
Read = 'read',
|
||||
// (undocumented)
|
||||
Update = 'update',
|
||||
}
|
||||
|
||||
// @public
|
||||
export type PermissionAttributes = {
|
||||
action?: PermissionAction;
|
||||
};
|
||||
|
||||
// @public
|
||||
export class PermissionClient {
|
||||
constructor(options: { discoveryApi: DiscoveryApi });
|
||||
authorize(
|
||||
requests: AuthorizeRequest[],
|
||||
options?: AuthorizeRequestOptions,
|
||||
): Promise<AuthorizeResponse[]>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type PermissionCondition<TParams extends any[] = any> = {
|
||||
rule: string;
|
||||
params: TParams;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type PermissionCriteria =
|
||||
| {
|
||||
allOf: PermissionCriteria[];
|
||||
}
|
||||
| {
|
||||
anyOf: PermissionCriteria[];
|
||||
}
|
||||
| PermissionCondition<any>;
|
||||
|
||||
// @public
|
||||
export type PermissionJSON = {
|
||||
name: string;
|
||||
attributes: PermissionAttributes;
|
||||
resourceType?: string;
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "@backstage/permission-common",
|
||||
"description": "Isomorphic types and client for Backstage permissions and authorization",
|
||||
"version": "0.1.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": true,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/permission-common"
|
||||
},
|
||||
"keywords": [
|
||||
"backstage",
|
||||
"permissions"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli build --outputs cjs,types",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test",
|
||||
"prepack": "backstage-cli prepack",
|
||||
"postpack": "backstage-cli postpack",
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/backstage/backstage/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/errors": "^0.1.2",
|
||||
"cross-fetch": "^3.0.6",
|
||||
"uuid": "^8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.8.0",
|
||||
"@types/jest": "^26.0.7",
|
||||
"msw": "^0.35.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
PermissionAction,
|
||||
PermissionAttributes,
|
||||
PermissionJSON,
|
||||
} from './types/permission';
|
||||
|
||||
/**
|
||||
* A permission that can be checked through authorization.
|
||||
*
|
||||
* Permissions are the "what" part of authorization, the action to be performed. This may be reading
|
||||
* an entity from the catalog, executing a software template, or any other action a plugin author
|
||||
* may wish to protect.
|
||||
*
|
||||
* To evaluate authorization, a permission is paired with a Backstage identity (the "who") and
|
||||
* evaluated using an authorization policy.
|
||||
* @public
|
||||
*/
|
||||
export class Permission {
|
||||
constructor(
|
||||
readonly name: string,
|
||||
readonly attributes: PermissionAttributes,
|
||||
readonly resourceType?: string,
|
||||
) {}
|
||||
|
||||
is(permission: Permission) {
|
||||
return this.name === permission.name;
|
||||
}
|
||||
|
||||
get isCreate() {
|
||||
return this.attributes.action === PermissionAction.Create;
|
||||
}
|
||||
|
||||
get isRead() {
|
||||
return this.attributes.action === PermissionAction.Read;
|
||||
}
|
||||
|
||||
get isUpdate() {
|
||||
return this.attributes.action === PermissionAction.Update;
|
||||
}
|
||||
|
||||
get isDelete() {
|
||||
return this.attributes.action === PermissionAction.Delete;
|
||||
}
|
||||
|
||||
toJSON(): PermissionJSON {
|
||||
return {
|
||||
name: this.name,
|
||||
attributes: this.attributes,
|
||||
resourceType: this.resourceType,
|
||||
};
|
||||
}
|
||||
|
||||
static create({
|
||||
name,
|
||||
attributes,
|
||||
resourceType,
|
||||
}: PermissionJSON): Permission {
|
||||
return new Permission(name, attributes, resourceType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { RestContext, rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { PermissionClient } from './PermissionClient';
|
||||
import { AuthorizeResult, Identified, AuthorizeRequestJSON } from './types/api';
|
||||
import { DiscoveryApi } from './types/discovery';
|
||||
import { Permission } from './Permission';
|
||||
|
||||
const server = setupServer();
|
||||
const token = 'fake-token';
|
||||
|
||||
const mockBaseUrl = 'http://backstage:9191/i-am-a-mock-base';
|
||||
const discoveryApi: DiscoveryApi = {
|
||||
async getBaseUrl() {
|
||||
return mockBaseUrl;
|
||||
},
|
||||
};
|
||||
const client: PermissionClient = new PermissionClient({ discoveryApi });
|
||||
|
||||
const mockPermission = Permission.create({
|
||||
name: 'test.permission',
|
||||
attributes: {},
|
||||
resourceType: 'test-resource',
|
||||
});
|
||||
|
||||
const mockAuthorizeRequest = {
|
||||
permission: mockPermission,
|
||||
resourceRef: 'foo',
|
||||
};
|
||||
|
||||
describe('PermissionClient', () => {
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
|
||||
afterAll(() => server.close());
|
||||
afterEach(() => server.resetHandlers());
|
||||
|
||||
describe('authorize', () => {
|
||||
const mockAuthorizeHandler = jest.fn((req, res, { json }: RestContext) => {
|
||||
const responses = req.body.map((a: Identified<AuthorizeRequestJSON>) => ({
|
||||
id: a.id,
|
||||
result: AuthorizeResult.ALLOW,
|
||||
}));
|
||||
|
||||
return res(json(responses));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
server.use(rest.post(`${mockBaseUrl}/authorize`, mockAuthorizeHandler));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should fetch entities from correct endpoint', async () => {
|
||||
await client.authorize([mockAuthorizeRequest]);
|
||||
expect(mockAuthorizeHandler).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should include a request body', async () => {
|
||||
await client.authorize([mockAuthorizeRequest]);
|
||||
|
||||
const request = mockAuthorizeHandler.mock.calls[0][0];
|
||||
expect(request.body[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
permission: mockPermission,
|
||||
resourceRef: 'foo',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should return the response from the fetch request', async () => {
|
||||
const response = await client.authorize([mockAuthorizeRequest]);
|
||||
expect(response[0]).toEqual(
|
||||
expect.objectContaining({ result: AuthorizeResult.ALLOW }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not include authorization headers if no token is supplied', async () => {
|
||||
await client.authorize([mockAuthorizeRequest]);
|
||||
|
||||
const request = mockAuthorizeHandler.mock.calls[0][0];
|
||||
expect(request.headers.has('authorization')).toEqual(false);
|
||||
});
|
||||
|
||||
it('should include correctly-constructed authorization header if token is supplied', async () => {
|
||||
await client.authorize([mockAuthorizeRequest], { token });
|
||||
|
||||
const request = mockAuthorizeHandler.mock.calls[0][0];
|
||||
expect(request.headers.get('authorization')).toEqual('Bearer fake-token');
|
||||
});
|
||||
|
||||
it('should forward response errors', async () => {
|
||||
mockAuthorizeHandler.mockImplementationOnce(
|
||||
(_req, res, { status }: RestContext) => {
|
||||
return res(status(401));
|
||||
},
|
||||
);
|
||||
await expect(
|
||||
client.authorize([mockAuthorizeRequest], { token }),
|
||||
).rejects.toThrowError(/request failed with 401/i);
|
||||
});
|
||||
|
||||
it('should reject invalid responses', async () => {
|
||||
mockAuthorizeHandler.mockImplementationOnce(
|
||||
(_req, res, { json }: RestContext) => {
|
||||
return res(json([{ id: 'wrong-id', result: AuthorizeResult.ALLOW }]));
|
||||
},
|
||||
);
|
||||
await expect(
|
||||
client.authorize([mockAuthorizeRequest], { token }),
|
||||
).rejects.toThrowError(/Unexpected authorization response/i);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import fetch from 'cross-fetch';
|
||||
import * as uuid from 'uuid';
|
||||
import {
|
||||
AuthorizeResult,
|
||||
AuthorizeRequest,
|
||||
AuthorizeResponse,
|
||||
AuthorizeRequestJSON,
|
||||
Identified,
|
||||
} from './types/api';
|
||||
import { DiscoveryApi } from './types/discovery';
|
||||
|
||||
/**
|
||||
* Options for authorization requests; currently only an optional auth token.
|
||||
* @public
|
||||
*/
|
||||
export type AuthorizeRequestOptions = {
|
||||
token?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* An isomorphic client for requesting authorization for Backstage permissions.
|
||||
* @public
|
||||
*/
|
||||
export class PermissionClient {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
|
||||
constructor(options: { discoveryApi: DiscoveryApi }) {
|
||||
this.discoveryApi = options.discoveryApi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request authorization from the permission-backend for the given set of permissions.
|
||||
*
|
||||
* Authorization requests check that a given Backstage user can perform a protected operation,
|
||||
* potentially for a specific resource (such as a catalog entity). The Backstage identity token
|
||||
* should be included in the `options` if available.
|
||||
*
|
||||
* Permissions can be imported from plugins exposing them, such as `catalogEntityReadPermission`.
|
||||
*
|
||||
* The response will be either ALLOW or DENY when either the permission has no resourceType, or a
|
||||
* resourceRef is provided in the request. For permissions with a resourceType, CONDITIONAL may be
|
||||
* returned if no resourceRef is provided in the request. Conditional responses are intended only
|
||||
* for backends which have access to the data source for permissioned resources, so that filters
|
||||
* can be applied when loading collections of resources.
|
||||
* @public
|
||||
*/
|
||||
async authorize(
|
||||
requests: AuthorizeRequest[],
|
||||
options?: AuthorizeRequestOptions,
|
||||
): Promise<AuthorizeResponse[]> {
|
||||
const identifiedRequests: Identified<AuthorizeRequestJSON>[] = requests.map(
|
||||
request => ({
|
||||
id: uuid.v4(),
|
||||
permission: request.permission.toJSON(),
|
||||
resourceRef: request.resourceRef,
|
||||
}),
|
||||
);
|
||||
|
||||
const permissionApi = await this.discoveryApi.getBaseUrl('permission');
|
||||
const response = await fetch(`${permissionApi}/authorize`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(identifiedRequests),
|
||||
headers: {
|
||||
...this.getAuthorizationHeader(options?.token),
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
const identifiedResponses = await response.json();
|
||||
this.assertValidResponses(identifiedRequests, identifiedResponses);
|
||||
|
||||
const responsesById = identifiedResponses.reduce((acc, r) => {
|
||||
acc[r.id] = r;
|
||||
return acc;
|
||||
}, {} as Record<string, Identified<AuthorizeResponse>>);
|
||||
|
||||
return identifiedRequests.map(request => responsesById[request.id]);
|
||||
}
|
||||
|
||||
private getAuthorizationHeader(token?: string): Record<string, string> {
|
||||
return token ? { Authorization: `Bearer ${token}` } : {};
|
||||
}
|
||||
|
||||
private assertValidResponses(
|
||||
requests: Identified<AuthorizeRequestJSON>[],
|
||||
json: any,
|
||||
): asserts json is Identified<AuthorizeResponse>[] {
|
||||
const responses = Array.isArray(json) ? json : [];
|
||||
const authorizedResponses: Identified<AuthorizeResponse>[] =
|
||||
responses.filter(
|
||||
(r: any): r is Identified<AuthorizeResponse> =>
|
||||
typeof r === 'object' &&
|
||||
typeof r.id === 'string' &&
|
||||
r.result in AuthorizeResult,
|
||||
);
|
||||
const responseIds = authorizedResponses.map(r => r.id);
|
||||
const hasAllRequestIds = requests.every(r => responseIds.includes(r.id));
|
||||
if (!hasAllRequestIds) {
|
||||
throw new Error(
|
||||
'Unexpected authorization response from permission-backend',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Isomorphic types and client for Backstage permissions and authorization
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
export * from './types';
|
||||
export * from './Permission';
|
||||
export * from './PermissionClient';
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Permission } from '../Permission';
|
||||
import { PermissionJSON } from './permission';
|
||||
|
||||
export type Identified<T> = T & { id: string };
|
||||
|
||||
/**
|
||||
* The result of an authorization request.
|
||||
* @public
|
||||
*/
|
||||
export enum AuthorizeResult {
|
||||
/**
|
||||
* The authorization request is denied.
|
||||
*/
|
||||
DENY = 'DENY',
|
||||
/**
|
||||
* The authorization request is allowed.
|
||||
*/
|
||||
ALLOW = 'ALLOW',
|
||||
/**
|
||||
* The authorization request is allowed if the provided conditions are met.
|
||||
*/
|
||||
CONDITIONAL = 'CONDITIONAL',
|
||||
}
|
||||
|
||||
/**
|
||||
* An authorization request for {@link PermissionClient#authorize}.
|
||||
* @public
|
||||
*/
|
||||
export type AuthorizeRequest = {
|
||||
permission: Permission;
|
||||
resourceRef?: string;
|
||||
};
|
||||
|
||||
export type AuthorizeRequestJSON = {
|
||||
permission: PermissionJSON;
|
||||
resourceRef?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A condition returned with a CONDITIONAL authorization response.
|
||||
*
|
||||
* Conditions are a reference to a rule defined by a plugin, and parameters to apply the rule. For
|
||||
* example, a rule might be `isOwner` from the catalog-backend, and params may be a list of entity
|
||||
* claims from a identity token.
|
||||
* @public
|
||||
*/
|
||||
export type PermissionCondition<TParams extends any[] = any> = {
|
||||
rule: string;
|
||||
params: TParams;
|
||||
};
|
||||
|
||||
/**
|
||||
* Composes several {@link PermissionCondition}s as criteria with a nested AND/OR structure.
|
||||
* @public
|
||||
*/
|
||||
export type PermissionCriteria =
|
||||
| { allOf: PermissionCriteria[] }
|
||||
| { anyOf: PermissionCriteria[] }
|
||||
| PermissionCondition<any>;
|
||||
|
||||
/**
|
||||
* An authorization response from {@link PermissionClient#authorize}.
|
||||
* @public
|
||||
*/
|
||||
export type AuthorizeResponse =
|
||||
| { result: AuthorizeResult.ALLOW | AuthorizeResult.DENY }
|
||||
| {
|
||||
result: AuthorizeResult.CONDITIONAL;
|
||||
conditions: PermissionCriteria;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a copy of the core DiscoveryApi, to avoid importing core.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type DiscoveryApi = {
|
||||
getBaseUrl(pluginId: string): Promise<string>;
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type {
|
||||
AuthorizeRequest,
|
||||
AuthorizeResponse,
|
||||
AuthorizeResult,
|
||||
PermissionCondition,
|
||||
PermissionCriteria,
|
||||
} from './api';
|
||||
export type { DiscoveryApi } from './discovery';
|
||||
export { PermissionAction } from './permission';
|
||||
export type { PermissionAttributes, PermissionJSON } from './permission';
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The basic operation being performed in relation to this permission, expressed as a CRUD action.
|
||||
* @public
|
||||
*/
|
||||
export enum PermissionAction {
|
||||
Create = 'create',
|
||||
Read = 'read',
|
||||
Update = 'update',
|
||||
Delete = 'delete',
|
||||
}
|
||||
|
||||
/**
|
||||
* The attributes related to a given permission; these should be generic and widely applicable to
|
||||
* all permissions in the system.
|
||||
* @public
|
||||
*/
|
||||
export type PermissionAttributes = {
|
||||
action?: PermissionAction;
|
||||
};
|
||||
|
||||
/**
|
||||
* JSON serializable representation of a {@link Permission}.
|
||||
* @public
|
||||
*/
|
||||
export type PermissionJSON = {
|
||||
name: string;
|
||||
attributes: PermissionAttributes;
|
||||
resourceType?: string;
|
||||
};
|
||||
Reference in New Issue
Block a user