@backstage/plugin-permission-common
Advanced tools
Comparing version 0.5.3 to 0.6.0-next.0
# @backstage/plugin-permission-common | ||
## 0.6.0-next.0 | ||
### Minor Changes | ||
- 8012ac46a0: Add `resourceType` property to `PermissionCondition` type to allow matching them with `ResourcePermission` instances. | ||
- c98d271466: Refactor api types into more specific, decoupled names. | ||
- **BREAKING:** | ||
- Renamed `AuthorizeDecision` to `EvaluatePermissionResponse` | ||
- Renamed `AuthorizeQuery` to `EvaluatePermissionRequest` | ||
- Renamed `AuthorizeRequest` to `EvaluatePermissionRequestBatch` | ||
- Renamed `AuthorizeResponse` to `EvaluatePermissionResponseBatch` | ||
- Renamed `Identified` to `IdentifiedPermissionMessage` | ||
- Add `PermissionMessageBatch` helper type | ||
- Add `ConditionalPolicyDecision`, `DefinitivePolicyDecision`, and `PolicyDecision` types from `@backstage/plugin-permission-node` | ||
### Patch Changes | ||
- 8012ac46a0: Add `isPermission` helper method. | ||
- 95284162d6: - Add more specific `Permission` types. | ||
- Add `createPermission` helper to infer the appropriate type for some permission input. | ||
- Add `isResourcePermission` helper to refine Permissions to ResourcePermissions. | ||
## 0.5.3 | ||
@@ -4,0 +27,0 @@ |
@@ -40,2 +40,11 @@ 'use strict'; | ||
function isPermission(permission, comparedPermission) { | ||
return permission.name === comparedPermission.name; | ||
} | ||
function isResourcePermission(permission, resourceType) { | ||
if (!("resourceType" in permission)) { | ||
return false; | ||
} | ||
return !resourceType || permission.resourceType === resourceType; | ||
} | ||
function isCreatePermission(permission) { | ||
@@ -54,4 +63,25 @@ return permission.attributes.action === "create"; | ||
function createPermission({ | ||
name, | ||
attributes, | ||
resourceType | ||
}) { | ||
if (resourceType) { | ||
return { | ||
type: "resource", | ||
name, | ||
attributes, | ||
resourceType | ||
}; | ||
} | ||
return { | ||
type: "basic", | ||
name, | ||
attributes | ||
}; | ||
} | ||
const permissionCriteriaSchema = zod.z.lazy(() => zod.z.object({ | ||
rule: zod.z.string(), | ||
resourceType: zod.z.string(), | ||
params: zod.z.array(zod.z.unknown()) | ||
@@ -120,6 +150,9 @@ }).strict().or(zod.z.object({ anyOf: zod.z.array(permissionCriteriaSchema).nonempty() }).strict()).or(zod.z.object({ allOf: zod.z.array(permissionCriteriaSchema).nonempty() }).strict()).or(zod.z.object({ not: permissionCriteriaSchema }).strict())); | ||
exports.PermissionClient = PermissionClient; | ||
exports.createPermission = createPermission; | ||
exports.isCreatePermission = isCreatePermission; | ||
exports.isDeletePermission = isDeletePermission; | ||
exports.isPermission = isPermission; | ||
exports.isReadPermission = isReadPermission; | ||
exports.isResourcePermission = isResourcePermission; | ||
exports.isUpdatePermission = isUpdatePermission; | ||
//# sourceMappingURL=index.cjs.js.map |
@@ -12,13 +12,6 @@ import { Config } from '@backstage/config'; | ||
/** | ||
* 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. | ||
* Generic type for building {@link Permission} types. | ||
* @public | ||
*/ | ||
declare type Permission = { | ||
declare type PermissionBase<TType extends string, TFields extends object> = { | ||
/** | ||
@@ -34,10 +27,42 @@ * The name of the permission. | ||
attributes: PermissionAttributes; | ||
} & { | ||
/** | ||
* Some permissions can be authorized based on characteristics of a resource | ||
* such a catalog entity. For these permissions, the resourceType field | ||
* denotes the type of the resource whose resourceRef should be passed when | ||
* String value indicating the type of the permission (e.g. 'basic', | ||
* 'resource'). The allowed authorization flows in the permission system | ||
* depend on the type. For example, a `resourceRef` should only be provided | ||
* when authorizing permissions of type 'resource'. | ||
*/ | ||
type: TType; | ||
} & TFields; | ||
/** | ||
* A permission that can be checked through authorization. | ||
* | ||
* @remarks | ||
* | ||
* 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 | ||
*/ | ||
declare type Permission = BasicPermission | ResourcePermission; | ||
/** | ||
* A standard {@link Permission} with no additional capabilities or restrictions. | ||
* @public | ||
*/ | ||
declare type BasicPermission = PermissionBase<'basic', {}>; | ||
/** | ||
* ResourcePermissions are {@link Permission}s that can be authorized based on | ||
* characteristics of a resource such a catalog entity. | ||
* @public | ||
*/ | ||
declare type ResourcePermission<TResourceType extends string = string> = PermissionBase<'resource', { | ||
/** | ||
* Denotes the type of the resource whose resourceRef should be passed when | ||
* authorizing. | ||
*/ | ||
resourceType?: string; | ||
}; | ||
resourceType: TResourceType; | ||
}>; | ||
/** | ||
@@ -48,3 +73,3 @@ * A client interacting with the permission backend can implement this authorizer interface. | ||
interface PermissionAuthorizer { | ||
authorize(queries: AuthorizeQuery[], options?: AuthorizeRequestOptions): Promise<AuthorizeDecision[]>; | ||
authorize(requests: EvaluatePermissionRequest[], options?: AuthorizeRequestOptions): Promise<EvaluatePermissionResponse[]>; | ||
} | ||
@@ -64,6 +89,13 @@ /** | ||
*/ | ||
declare type Identified<T> = T & { | ||
declare type IdentifiedPermissionMessage<T> = T & { | ||
id: string; | ||
}; | ||
/** | ||
* A batch of request or response items. | ||
* @public | ||
*/ | ||
declare type PermissionMessageBatch<T> = { | ||
items: IdentifiedPermissionMessage<T>[]; | ||
}; | ||
/** | ||
* The result of an authorization request. | ||
@@ -87,17 +119,37 @@ * @public | ||
/** | ||
* An individual authorization request for {@link PermissionClient#authorize}. | ||
* A definitive decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}. | ||
* | ||
* @remarks | ||
* | ||
* This indicates that the policy unconditionally allows (or denies) the request. | ||
* | ||
* @public | ||
*/ | ||
declare type AuthorizeQuery = { | ||
permission: Permission; | ||
resourceRef?: string; | ||
declare type DefinitivePolicyDecision = { | ||
result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; | ||
}; | ||
/** | ||
* A batch of authorization requests from {@link PermissionClient#authorize}. | ||
* A conditional decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}. | ||
* | ||
* @remarks | ||
* | ||
* This indicates that the policy allows authorization for the request, given that the returned | ||
* conditions hold when evaluated. The conditions will be evaluated by the corresponding plugin | ||
* which knows about the referenced permission rules. | ||
* | ||
* @public | ||
*/ | ||
declare type AuthorizeRequest = { | ||
items: Identified<AuthorizeQuery>[]; | ||
declare type ConditionalPolicyDecision = { | ||
result: AuthorizeResult.CONDITIONAL; | ||
pluginId: string; | ||
resourceType: string; | ||
conditions: PermissionCriteria<PermissionCondition>; | ||
}; | ||
/** | ||
* A decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}. | ||
* | ||
* @public | ||
*/ | ||
declare type PolicyDecision = DefinitivePolicyDecision | ConditionalPolicyDecision; | ||
/** | ||
* A condition returned with a CONDITIONAL authorization response. | ||
@@ -110,3 +162,4 @@ * | ||
*/ | ||
declare type PermissionCondition<TParams extends unknown[] = unknown[]> = { | ||
declare type PermissionCondition<TResourceType extends string = string, TParams extends unknown[] = unknown[]> = { | ||
resourceType: TResourceType; | ||
rule: string; | ||
@@ -147,18 +200,31 @@ params: TParams; | ||
/** | ||
* An individual authorization response from {@link PermissionClient#authorize}. | ||
* An individual request sent to the permission backend. | ||
* @public | ||
*/ | ||
declare type AuthorizeDecision = { | ||
result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; | ||
} | { | ||
result: AuthorizeResult.CONDITIONAL; | ||
conditions: PermissionCriteria<PermissionCondition>; | ||
declare type EvaluatePermissionRequest = { | ||
permission: Permission; | ||
resourceRef?: string; | ||
}; | ||
/** | ||
* A batch of authorization responses from {@link PermissionClient#authorize}. | ||
* A batch of requests sent to the permission backend. | ||
* @public | ||
*/ | ||
declare type AuthorizeResponse = { | ||
items: Identified<AuthorizeDecision>[]; | ||
}; | ||
declare type EvaluatePermissionRequestBatch = PermissionMessageBatch<EvaluatePermissionRequest>; | ||
/** | ||
* An individual response from the permission backend. | ||
* | ||
* @remarks | ||
* | ||
* This response type is an alias of {@link PolicyDecision} to maintain separation between the | ||
* {@link @backstage/plugin-permission-node#PermissionPolicy} interface and the permission backend | ||
* api. They may diverge at some point in the future. The response | ||
* | ||
* @public | ||
*/ | ||
declare type EvaluatePermissionResponse = PolicyDecision; | ||
/** | ||
* A batch of responses from the permission backend. | ||
* @public | ||
*/ | ||
declare type EvaluatePermissionResponseBatch = PermissionMessageBatch<EvaluatePermissionResponse>; | ||
@@ -175,2 +241,14 @@ /** | ||
/** | ||
* Check if the two parameters are equivalent permissions. | ||
* @public | ||
*/ | ||
declare function isPermission<T extends Permission>(permission: Permission, comparedPermission: T): permission is T; | ||
/** | ||
* Check if a given permission is a {@link ResourcePermission}. When | ||
* `resourceType` is supplied as the second parameter, also checks if | ||
* the permission has the specified resource type. | ||
* @public | ||
*/ | ||
declare function isResourcePermission<T extends string = string>(permission: Permission, resourceType?: T): permission is ResourcePermission<T>; | ||
/** | ||
* Check if a given permission is related to a create action. | ||
@@ -197,2 +275,23 @@ * @public | ||
/** | ||
* Utility function for creating a valid {@link ResourcePermission}, inferring | ||
* the appropriate type and resource type parameter. | ||
* | ||
* @public | ||
*/ | ||
declare function createPermission<TResourceType extends string>(input: { | ||
name: string; | ||
attributes: PermissionAttributes; | ||
resourceType: TResourceType; | ||
}): ResourcePermission<TResourceType>; | ||
/** | ||
* Utility function for creating a valid {@link BasicPermission}. | ||
* | ||
* @public | ||
*/ | ||
declare function createPermission(input: { | ||
name: string; | ||
attributes: PermissionAttributes; | ||
}): BasicPermission; | ||
/** | ||
* An isomorphic client for requesting authorization for Backstage permissions. | ||
@@ -224,3 +323,3 @@ * @public | ||
*/ | ||
authorize(queries: AuthorizeQuery[], options?: AuthorizeRequestOptions): Promise<AuthorizeDecision[]>; | ||
authorize(queries: EvaluatePermissionRequest[], options?: AuthorizeRequestOptions): Promise<EvaluatePermissionResponse[]>; | ||
private getAuthorizationHeader; | ||
@@ -230,2 +329,2 @@ private assertValidResponse; | ||
export { AllOfCriteria, AnyOfCriteria, AuthorizeDecision, AuthorizeQuery, AuthorizeRequest, AuthorizeRequestOptions, AuthorizeResponse, AuthorizeResult, DiscoveryApi, Identified, NotCriteria, Permission, PermissionAttributes, PermissionAuthorizer, PermissionClient, PermissionCondition, PermissionCriteria, isCreatePermission, isDeletePermission, isReadPermission, isUpdatePermission }; | ||
export { AllOfCriteria, AnyOfCriteria, AuthorizeRequestOptions, AuthorizeResult, BasicPermission, ConditionalPolicyDecision, DefinitivePolicyDecision, DiscoveryApi, EvaluatePermissionRequest, EvaluatePermissionRequestBatch, EvaluatePermissionResponse, EvaluatePermissionResponseBatch, IdentifiedPermissionMessage, NotCriteria, Permission, PermissionAttributes, PermissionAuthorizer, PermissionBase, PermissionClient, PermissionCondition, PermissionCriteria, PermissionMessageBatch, PolicyDecision, ResourcePermission, createPermission, isCreatePermission, isDeletePermission, isPermission, isReadPermission, isResourcePermission, isUpdatePermission }; |
@@ -13,2 +13,11 @@ import { ResponseError } from '@backstage/errors'; | ||
function isPermission(permission, comparedPermission) { | ||
return permission.name === comparedPermission.name; | ||
} | ||
function isResourcePermission(permission, resourceType) { | ||
if (!("resourceType" in permission)) { | ||
return false; | ||
} | ||
return !resourceType || permission.resourceType === resourceType; | ||
} | ||
function isCreatePermission(permission) { | ||
@@ -27,4 +36,25 @@ return permission.attributes.action === "create"; | ||
function createPermission({ | ||
name, | ||
attributes, | ||
resourceType | ||
}) { | ||
if (resourceType) { | ||
return { | ||
type: "resource", | ||
name, | ||
attributes, | ||
resourceType | ||
}; | ||
} | ||
return { | ||
type: "basic", | ||
name, | ||
attributes | ||
}; | ||
} | ||
const permissionCriteriaSchema = z.lazy(() => z.object({ | ||
rule: z.string(), | ||
resourceType: z.string(), | ||
params: z.array(z.unknown()) | ||
@@ -91,3 +121,3 @@ }).strict().or(z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }).strict()).or(z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }).strict()).or(z.object({ not: permissionCriteriaSchema }).strict())); | ||
export { AuthorizeResult, PermissionClient, isCreatePermission, isDeletePermission, isReadPermission, isUpdatePermission }; | ||
export { AuthorizeResult, PermissionClient, createPermission, isCreatePermission, isDeletePermission, isPermission, isReadPermission, isResourcePermission, isUpdatePermission }; | ||
//# sourceMappingURL=index.esm.js.map |
{ | ||
"name": "@backstage/plugin-permission-common", | ||
"description": "Isomorphic types and client for Backstage permissions and authorization", | ||
"version": "0.5.3", | ||
"version": "0.6.0-next.0", | ||
"main": "dist/index.cjs.js", | ||
@@ -51,8 +51,8 @@ "types": "dist/index.d.ts", | ||
"devDependencies": { | ||
"@backstage/cli": "^0.16.0", | ||
"@backstage/cli": "^0.17.0-next.1", | ||
"@types/jest": "^26.0.7", | ||
"msw": "^0.35.0" | ||
}, | ||
"gitHead": "e9496f746b31600dbfac7fa76987479e66426257", | ||
"gitHead": "57d12dcc35aeb6c33b09e51d1efc3408c574f109", | ||
"module": "dist/index.esm.js" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
75872
600