@backstage/plugin-permission-node 0.7.7-next.0 → 0.7.7-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/alpha/package.json +6 -0
- package/dist/alpha.cjs.js +12 -0
- package/dist/alpha.cjs.js.map +1 -0
- package/dist/alpha.d.ts +19 -0
- package/dist/index.cjs.js +10 -0
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +25 -18
- package/package.json +24 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @backstage/plugin-permission-node
|
|
2
2
|
|
|
3
|
+
## 0.7.7-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 788f0f5a152: Introduced alpha export of the `policyExtensionPoint` for use in the new backend system.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/backend-common@0.18.4-next.2
|
|
10
|
+
- @backstage/backend-plugin-api@0.5.1-next.2
|
|
11
|
+
- @backstage/config@1.0.7
|
|
12
|
+
- @backstage/errors@1.1.5
|
|
13
|
+
- @backstage/plugin-auth-node@0.2.13-next.2
|
|
14
|
+
- @backstage/plugin-permission-common@0.7.5-next.0
|
|
15
|
+
|
|
16
|
+
## 0.7.7-next.1
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 71fd0966d10: Added createConditionAuthorizer utility function, which takes some permission conditions and returns a function that returns a definitive authorization result given a decision and a resource.
|
|
21
|
+
- 1e4f5e91b8e: Bump `zod` and `zod-to-json-schema` dependencies.
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @backstage/plugin-permission-common@0.7.5-next.0
|
|
24
|
+
- @backstage/backend-common@0.18.4-next.1
|
|
25
|
+
- @backstage/config@1.0.7
|
|
26
|
+
- @backstage/errors@1.1.5
|
|
27
|
+
- @backstage/plugin-auth-node@0.2.13-next.1
|
|
28
|
+
|
|
3
29
|
## 0.7.7-next.0
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
6
|
+
|
|
7
|
+
const policyExtensionPoint = backendPluginApi.createExtensionPoint({
|
|
8
|
+
id: "permission.policy"
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
exports.policyExtensionPoint = policyExtensionPoint;
|
|
12
|
+
//# sourceMappingURL=alpha.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\nimport { PermissionPolicy } from '@backstage/plugin-permission-node';\n\n/**\n * Allows supplying policies to the permissions backend\n *\n * @alpha\n */\nexport type PolicyExtensionPoint = {\n setPolicy(policy: PermissionPolicy): void;\n};\n\n/**\n * Allows supplying policies to the permissions backend\n *\n * @alpha\n */\nexport const policyExtensionPoint = createExtensionPoint<PolicyExtensionPoint>({\n id: 'permission.policy',\n});\n"],"names":["createExtensionPoint"],"mappings":";;;;;;AAiCO,MAAM,uBAAuBA,qCAA2C,CAAA;AAAA,EAC7E,EAAI,EAAA,mBAAA;AACN,CAAC;;;;"}
|
package/dist/alpha.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
+
import { PermissionPolicy } from '@backstage/plugin-permission-node';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Allows supplying policies to the permissions backend
|
|
6
|
+
*
|
|
7
|
+
* @alpha
|
|
8
|
+
*/
|
|
9
|
+
type PolicyExtensionPoint = {
|
|
10
|
+
setPolicy(policy: PermissionPolicy): void;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Allows supplying policies to the permissions backend
|
|
14
|
+
*
|
|
15
|
+
* @alpha
|
|
16
|
+
*/
|
|
17
|
+
declare const policyExtensionPoint: _backstage_backend_plugin_api.ExtensionPoint<PolicyExtensionPoint>;
|
|
18
|
+
|
|
19
|
+
export { PolicyExtensionPoint, policyExtensionPoint };
|
package/dist/index.cjs.js
CHANGED
|
@@ -131,6 +131,15 @@ const applyConditions = (criteria, resource, getRule) => {
|
|
|
131
131
|
}
|
|
132
132
|
return rule.apply(resource, (_b = criteria.params) != null ? _b : {});
|
|
133
133
|
};
|
|
134
|
+
const createConditionAuthorizer = (rules) => {
|
|
135
|
+
const getRule = createGetRule(rules);
|
|
136
|
+
return (decision, resource) => {
|
|
137
|
+
if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
|
|
138
|
+
return applyConditions(decision.conditions, resource, getRule);
|
|
139
|
+
}
|
|
140
|
+
return decision.result === pluginPermissionCommon.AuthorizeResult.ALLOW;
|
|
141
|
+
};
|
|
142
|
+
};
|
|
134
143
|
function createPermissionIntegrationRouter(options) {
|
|
135
144
|
const router = Router__default["default"]();
|
|
136
145
|
router.use(express__default["default"].json());
|
|
@@ -247,6 +256,7 @@ class ServerPermissionClient {
|
|
|
247
256
|
}
|
|
248
257
|
|
|
249
258
|
exports.ServerPermissionClient = ServerPermissionClient;
|
|
259
|
+
exports.createConditionAuthorizer = createConditionAuthorizer;
|
|
250
260
|
exports.createConditionExports = createConditionExports;
|
|
251
261
|
exports.createConditionFactory = createConditionFactory;
|
|
252
262
|
exports.createConditionTransformer = createConditionTransformer;
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/integration/createConditionFactory.ts","../src/integration/createConditionExports.ts","../src/integration/util.ts","../src/integration/createConditionTransformer.ts","../src/integration/createPermissionIntegrationRouter.ts","../src/integration/createPermissionRule.ts","../src/ServerPermissionClient.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PermissionCondition,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\n\n/**\n * Creates a condition factory function for a given authorization rule and parameter types.\n *\n * @remarks\n *\n * For example, an isEntityOwner rule for catalog entities might take an array of entityRef strings.\n * The rule itself defines _how_ to check a given resource, whereas a condition also includes _what_\n * to verify.\n *\n * Plugin authors should generally use the {@link createConditionExports} in order to efficiently\n * create multiple condition factories. This helper should generally only be used to construct\n * condition factories for third-party rules that aren't part of the backend plugin with which\n * they're intended to integrate.\n *\n * @public\n */\nexport const createConditionFactory = <\n TResourceType extends string,\n TParams extends PermissionRuleParams = PermissionRuleParams,\n>(\n rule: PermissionRule<unknown, unknown, TResourceType, TParams>,\n) => {\n return (params: TParams): PermissionCondition<TResourceType, TParams> => {\n return {\n rule: rule.name,\n resourceType: rule.resourceType,\n params,\n };\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthorizeResult,\n ConditionalPolicyDecision,\n PermissionCondition,\n PermissionCriteria,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport { createConditionFactory } from './createConditionFactory';\n\n/**\n * A utility type for mapping a single {@link PermissionRule} to its\n * corresponding {@link @backstage/plugin-permission-common#PermissionCondition}.\n *\n * @public\n */\nexport type Condition<TRule> = TRule extends PermissionRule<\n any,\n any,\n infer TResourceType,\n infer TParams\n>\n ? undefined extends TParams\n ? () => PermissionCondition<TResourceType, TParams>\n : (params: TParams) => PermissionCondition<TResourceType, TParams>\n : never;\n\n/**\n * A utility type for mapping {@link PermissionRule}s to their corresponding\n * {@link @backstage/plugin-permission-common#PermissionCondition}s.\n *\n * @public\n */\nexport type Conditions<\n TRules extends Record<string, PermissionRule<any, any, any>>,\n> = {\n [Name in keyof TRules]: Condition<TRules[Name]>;\n};\n\n/**\n * Creates the recommended condition-related exports for a given plugin based on\n * the built-in {@link PermissionRule}s it supports.\n *\n * @remarks\n *\n * The function returns a `conditions` object containing a\n * {@link @backstage/plugin-permission-common#PermissionCondition} factory for\n * each of the supplied {@link PermissionRule}s, along with a\n * `createConditionalDecision` function which builds the wrapper object needed\n * to enclose conditions when authoring {@link PermissionPolicy}\n * implementations.\n *\n * Plugin authors should generally call this method with all the built-in\n * {@link PermissionRule}s the plugin supports, and export the resulting\n * `conditions` object and `createConditionalDecision` function so that they can\n * be used by {@link PermissionPolicy} authors.\n *\n * @public\n */\nexport const createConditionExports = <\n TResourceType extends string,\n TResource,\n TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,\n>(options: {\n pluginId: string;\n resourceType: TResourceType;\n rules: TRules;\n}): {\n conditions: Conditions<TRules>;\n createConditionalDecision: (\n permission: ResourcePermission<TResourceType>,\n conditions: PermissionCriteria<PermissionCondition<TResourceType>>,\n ) => ConditionalPolicyDecision;\n} => {\n const { pluginId, resourceType, rules } = options;\n\n return {\n conditions: Object.entries(rules).reduce(\n (acc, [key, rule]) => ({\n ...acc,\n [key]: createConditionFactory(rule),\n }),\n {} as Conditions<TRules>,\n ),\n createConditionalDecision: (\n _permission: ResourcePermission<TResourceType>,\n conditions: PermissionCriteria<PermissionCondition>,\n ) => ({\n result: AuthorizeResult.CONDITIONAL,\n pluginId,\n resourceType,\n conditions,\n }),\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AllOfCriteria,\n AnyOfCriteria,\n NotCriteria,\n PermissionCriteria,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\n\n/**\n * Prevent use of type parameter from contributing to type inference.\n *\n * https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-980401795\n * @ignore\n */\nexport type NoInfer<T> = T extends infer S ? S : never;\n\n/**\n * Utility function used to parse a PermissionCriteria\n * @param criteria - a PermissionCriteria\n * @public\n *\n * @returns `true` if the permission criteria is of type allOf,\n * narrowing down `criteria` to the specific type.\n */\nexport const isAndCriteria = <T>(\n criteria: PermissionCriteria<T>,\n): criteria is AllOfCriteria<T> =>\n Object.prototype.hasOwnProperty.call(criteria, 'allOf');\n\n/**\n * Utility function used to parse a PermissionCriteria of type\n * @param criteria - a PermissionCriteria\n * @public\n *\n * @returns `true` if the permission criteria is of type anyOf,\n * narrowing down `criteria` to the specific type.\n */\nexport const isOrCriteria = <T>(\n criteria: PermissionCriteria<T>,\n): criteria is AnyOfCriteria<T> =>\n Object.prototype.hasOwnProperty.call(criteria, 'anyOf');\n\n/**\n * Utility function used to parse a PermissionCriteria\n * @param criteria - a PermissionCriteria\n * @public\n *\n * @returns `true` if the permission criteria is of type not,\n * narrowing down `criteria` to the specific type.\n */\nexport const isNotCriteria = <T>(\n criteria: PermissionCriteria<T>,\n): criteria is NotCriteria<T> =>\n Object.prototype.hasOwnProperty.call(criteria, 'not');\n\nexport const createGetRule = <TResource, TQuery>(\n rules: PermissionRule<TResource, TQuery, string>[],\n) => {\n const rulesMap = new Map(Object.values(rules).map(rule => [rule.name, rule]));\n\n return (name: string): PermissionRule<TResource, TQuery, string> => {\n const rule = rulesMap.get(name);\n\n if (!rule) {\n throw new Error(`Unexpected permission rule: ${name}`);\n }\n\n return rule;\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { InputError } from '@backstage/errors';\nimport {\n AllOfCriteria,\n AnyOfCriteria,\n PermissionCondition,\n PermissionCriteria,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport {\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\n\nconst mapConditions = <TQuery>(\n criteria: PermissionCriteria<PermissionCondition>,\n getRule: (name: string) => PermissionRule<unknown, TQuery, string>,\n): PermissionCriteria<TQuery> => {\n if (isAndCriteria(criteria)) {\n return {\n allOf: criteria.allOf.map(child => mapConditions(child, getRule)),\n } as AllOfCriteria<TQuery>;\n } else if (isOrCriteria(criteria)) {\n return {\n anyOf: criteria.anyOf.map(child => mapConditions(child, getRule)),\n } as AnyOfCriteria<TQuery>;\n } else if (isNotCriteria(criteria)) {\n return {\n not: mapConditions(criteria.not, getRule),\n };\n }\n\n const rule = getRule(criteria.rule);\n const result = rule.paramsSchema?.safeParse(criteria.params);\n\n if (result && !result.success) {\n throw new InputError(`Parameters to rule are invalid`, result.error);\n }\n\n return rule.toQuery(criteria.params ?? {});\n};\n\n/**\n * A function which accepts {@link @backstage/plugin-permission-common#PermissionCondition}s\n * logically grouped in a {@link @backstage/plugin-permission-common#PermissionCriteria}\n * object, and transforms the {@link @backstage/plugin-permission-common#PermissionCondition}s\n * into plugin specific query fragments while retaining the enclosing criteria shape.\n *\n * @public\n */\nexport type ConditionTransformer<TQuery> = (\n conditions: PermissionCriteria<PermissionCondition>,\n) => PermissionCriteria<TQuery>;\n\n/**\n * A higher-order helper function which accepts an array of\n * {@link PermissionRule}s, and returns a {@link ConditionTransformer}\n * which transforms input conditions into equivalent plugin-specific\n * query fragments using the supplied rules.\n *\n * @public\n */\nexport const createConditionTransformer = <\n TQuery,\n TRules extends PermissionRule<any, TQuery, string>[],\n>(\n permissionRules: [...TRules],\n): ConditionTransformer<TQuery> => {\n const getRule = createGetRule(permissionRules);\n\n return conditions => mapConditions(conditions, getRule);\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express, { Response } from 'express';\nimport Router from 'express-promise-router';\nimport { z } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { InputError } from '@backstage/errors';\nimport { errorHandler } from '@backstage/backend-common';\nimport {\n AuthorizeResult,\n DefinitivePolicyDecision,\n IdentifiedPermissionMessage,\n Permission,\n PermissionCondition,\n PermissionCriteria,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport {\n NoInfer,\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\nimport { NotImplementedError } from '@backstage/errors';\n\nconst permissionCriteriaSchema: z.ZodSchema<\n PermissionCriteria<PermissionCondition>\n> = z.lazy(() =>\n z.union([\n z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }),\n z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }),\n z.object({ not: permissionCriteriaSchema }),\n z.object({\n rule: z.string(),\n resourceType: z.string(),\n params: z.record(z.any()).optional(),\n }),\n ]),\n);\n\nconst applyConditionsRequestSchema = z.object({\n items: z.array(\n z.object({\n id: z.string(),\n resourceRef: z.string(),\n resourceType: z.string(),\n conditions: permissionCriteriaSchema,\n }),\n ),\n});\n\n/**\n * A request to load the referenced resource and apply conditions in order to\n * finalize a conditional authorization response.\n *\n * @public\n */\nexport type ApplyConditionsRequestEntry = IdentifiedPermissionMessage<{\n resourceRef: string;\n resourceType: string;\n conditions: PermissionCriteria<PermissionCondition>;\n}>;\n\n/**\n * A batch of {@link ApplyConditionsRequestEntry} objects.\n *\n * @public\n */\nexport type ApplyConditionsRequest = {\n items: ApplyConditionsRequestEntry[];\n};\n\n/**\n * The result of applying the conditions, expressed as a definitive authorize\n * result of ALLOW or DENY.\n *\n * @public\n */\nexport type ApplyConditionsResponseEntry =\n IdentifiedPermissionMessage<DefinitivePolicyDecision>;\n\n/**\n * A batch of {@link ApplyConditionsResponseEntry} objects.\n *\n * @public\n */\nexport type ApplyConditionsResponse = {\n items: ApplyConditionsResponseEntry[];\n};\n\n/**\n * Serialized permission rules, with the paramsSchema\n * converted from a ZodSchema to a JsonSchema.\n *\n * @public\n */\nexport type MetadataResponseSerializedRule = {\n name: string;\n description: string;\n resourceType: string;\n paramsSchema?: ReturnType<typeof zodToJsonSchema>;\n};\n\n/**\n * Response type for the .metadata endpoint.\n *\n * @public\n */\nexport type MetadataResponse = {\n permissions?: Permission[];\n rules: MetadataResponseSerializedRule[];\n};\n\nconst applyConditions = <TResourceType extends string, TResource>(\n criteria: PermissionCriteria<PermissionCondition<TResourceType>>,\n resource: TResource | undefined,\n getRule: (name: string) => PermissionRule<TResource, unknown, TResourceType>,\n): boolean => {\n // If resource was not found, deny. This avoids leaking information from the\n // apply-conditions API which would allow a user to differentiate between\n // non-existent resources and resources to which they do not have access.\n if (resource === undefined) {\n return false;\n }\n\n if (isAndCriteria(criteria)) {\n return criteria.allOf.every(child =>\n applyConditions(child, resource, getRule),\n );\n } else if (isOrCriteria(criteria)) {\n return criteria.anyOf.some(child =>\n applyConditions(child, resource, getRule),\n );\n } else if (isNotCriteria(criteria)) {\n return !applyConditions(criteria.not, resource, getRule);\n }\n\n const rule = getRule(criteria.rule);\n const result = rule.paramsSchema?.safeParse(criteria.params);\n\n if (result && !result.success) {\n throw new InputError(`Parameters to rule are invalid`, result.error);\n }\n\n return rule.apply(resource, criteria.params ?? {});\n};\n\n/**\n * Options for creating a permission integration router specific\n * for a particular resource type.\n *\n * @public\n */\nexport type CreatePermissionIntegrationRouterResourceOptions<\n TResourceType extends string,\n TResource,\n> = {\n resourceType: TResourceType;\n permissions?: Array<Permission>;\n // Do not infer value of TResourceType from supplied rules.\n // instead only consider the resourceType parameter, and\n // consider any rules whose resource type does not match\n // to be an error.\n rules: PermissionRule<TResource, any, NoInfer<TResourceType>>[];\n getResources?: (\n resourceRefs: string[],\n ) => Promise<Array<TResource | undefined>>;\n};\n\n/**\n * Create an express Router which provides an authorization route to allow\n * integration between the permission backend and other Backstage backend\n * plugins. Plugin owners that wish to support conditional authorization for\n * their resources should add the router created by this function to their\n * express app inside their `createRouter` implementation.\n *\n * In case the `permissions` option is provided, the router also\n * provides a route that exposes permissions and routes of a plugin.\n *\n * @remarks\n *\n * To make this concrete, we can use the Backstage software catalog as an\n * example. The catalog has conditional rules around access to specific\n * _entities_ in the catalog. The _type_ of resource is captured here as\n * `resourceType`, a string identifier (`catalog-entity` in this example) that\n * can be provided with permission definitions. This is merely a _type_ to\n * verify that conditions in an authorization policy are constructed correctly,\n * not a reference to a specific resource.\n *\n * The `rules` parameter is an array of {@link PermissionRule}s that introduce\n * conditional filtering logic for resources; for the catalog, these are things\n * like `isEntityOwner` or `hasAnnotation`. Rules describe how to filter a list\n * of resources, and the `conditions` returned allow these rules to be applied\n * with specific parameters (such as 'group:default/team-a', or\n * 'backstage.io/edit-url').\n *\n * The `getResources` argument should load resources based on a reference\n * identifier. For the catalog, this is an\n * {@link @backstage/catalog-model#EntityRef}. For other plugins, this can be\n * any serialized format. This is used to construct the\n * `createPermissionIntegrationRouter`, a function to add an authorization route\n * to your backend plugin. This function will be called by the\n * `permission-backend` when authorization conditions relating to this plugin\n * need to be evaluated.\n *\n * @public\n */\nexport function createPermissionIntegrationRouter<\n TResourceType extends string,\n TResource,\n>(\n options: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n): express.Router;\n\n/**\n *\n * Create an express Router which provides a route that exposes\n * permissions and routes of a plugin.\n * @public\n */\nexport function createPermissionIntegrationRouter(options: {\n permissions: Array<Permission>;\n}): express.Router;\n\n/**\n * @public\n */\nexport function createPermissionIntegrationRouter<\n TResourceType extends string,\n TResource,\n>(\n options:\n | { permissions: Array<Permission> }\n | CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n): express.Router {\n const router = Router();\n router.use(express.json());\n\n const { permissions = [], rules = [] } = { rules: [], ...options };\n router.get('/.well-known/backstage/permissions/metadata', (_, res) => {\n const serializedRules: MetadataResponseSerializedRule[] = rules.map(\n rule => ({\n name: rule.name,\n description: rule.description,\n resourceType: rule.resourceType,\n paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})),\n }),\n );\n\n const responseJson: MetadataResponse = {\n permissions,\n rules: serializedRules,\n };\n\n return res.json(responseJson);\n });\n\n router.post(\n '/.well-known/backstage/permissions/apply-conditions',\n async (req, res: Response<ApplyConditionsResponse | string>) => {\n if (\n !isCreatePermissionIntegrationRouterResourceOptions(options) ||\n options.getResources === undefined\n ) {\n throw new NotImplementedError(\n `This plugin does not expose any permission rule or can't evaluate conditional decisions`,\n );\n }\n const { resourceType, getResources } = options;\n\n const getRule = createGetRule(rules);\n\n const assertValidResourceTypes = (\n requests: ApplyConditionsRequestEntry[],\n ) => {\n const invalidResourceTypes = requests\n .filter(request => request.resourceType !== resourceType)\n .map(request => request.resourceType);\n\n if (invalidResourceTypes.length) {\n throw new InputError(\n `Unexpected resource types: ${invalidResourceTypes.join(', ')}.`,\n );\n }\n };\n\n const parseResult = applyConditionsRequestSchema.safeParse(req.body);\n\n if (!parseResult.success) {\n throw new InputError(parseResult.error.toString());\n }\n\n const body = parseResult.data;\n\n assertValidResourceTypes(body.items);\n\n const resourceRefs = Array.from(\n new Set(body.items.map(({ resourceRef }) => resourceRef)),\n );\n const resourceArray = await getResources(resourceRefs);\n const resources = resourceRefs.reduce((acc, resourceRef, index) => {\n acc[resourceRef] = resourceArray[index];\n\n return acc;\n }, {} as Record<string, TResource | undefined>);\n\n return res.json({\n items: body.items.map(request => ({\n id: request.id,\n result: applyConditions(\n request.conditions,\n resources[request.resourceRef],\n getRule,\n )\n ? AuthorizeResult.ALLOW\n : AuthorizeResult.DENY,\n })),\n });\n },\n );\n\n router.use(errorHandler());\n\n return router;\n}\n\nfunction isCreatePermissionIntegrationRouterResourceOptions<\n TResourceType extends string,\n TResource,\n>(\n options:\n | { permissions: Array<Permission> }\n | CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n): options is CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n> {\n return (\n (\n options as CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >\n ).resourceType !== undefined\n );\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\n\n/**\n * Helper function to ensure that {@link PermissionRule} definitions are typed correctly.\n *\n * @public\n */\nexport const createPermissionRule = <\n TResource,\n TQuery,\n TResourceType extends string,\n TParams extends PermissionRuleParams = undefined,\n>(\n rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,\n) => rule;\n\n/**\n * Helper for making plugin-specific createPermissionRule functions, that have\n * the TResource and TQuery type parameters populated but infer the params from\n * the supplied rule. This helps ensure that rules created for this plugin use\n * consistent types for the resource and query.\n *\n * @public\n */\nexport const makeCreatePermissionRule =\n <TResource, TQuery, TResourceType extends string>() =>\n <TParams extends PermissionRuleParams = undefined>(\n rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,\n ) =>\n createPermissionRule(rule);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n TokenManager,\n PluginEndpointDiscovery,\n} from '@backstage/backend-common';\nimport { Config } from '@backstage/config';\nimport {\n AuthorizeResult,\n PermissionClient,\n PermissionEvaluator,\n AuthorizePermissionRequest,\n EvaluatorRequestOptions,\n AuthorizePermissionResponse,\n PolicyDecision,\n QueryPermissionRequest,\n} from '@backstage/plugin-permission-common';\n\n/**\n * A thin wrapper around\n * {@link @backstage/plugin-permission-common#PermissionClient} that allows all\n * service-to-service requests.\n * @public\n */\nexport class ServerPermissionClient implements PermissionEvaluator {\n private readonly permissionClient: PermissionClient;\n private readonly tokenManager: TokenManager;\n private readonly permissionEnabled: boolean;\n\n static fromConfig(\n config: Config,\n options: {\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n },\n ) {\n const { discovery, tokenManager } = options;\n const permissionClient = new PermissionClient({ discovery, config });\n const permissionEnabled =\n config.getOptionalBoolean('permission.enabled') ?? false;\n\n if (\n permissionEnabled &&\n (tokenManager as any).isInsecureServerTokenManager\n ) {\n throw new Error(\n 'Service-to-service authentication must be configured before enabling permissions. Read more here https://backstage.io/docs/auth/service-to-service-auth',\n );\n }\n\n return new ServerPermissionClient({\n permissionClient,\n tokenManager,\n permissionEnabled,\n });\n }\n\n private constructor(options: {\n permissionClient: PermissionClient;\n tokenManager: TokenManager;\n permissionEnabled: boolean;\n }) {\n this.permissionClient = options.permissionClient;\n this.tokenManager = options.tokenManager;\n this.permissionEnabled = options.permissionEnabled;\n }\n\n async authorizeConditional(\n queries: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<PolicyDecision[]> {\n return (await this.isEnabled(options?.token))\n ? this.permissionClient.authorizeConditional(queries, options)\n : queries.map(_ => ({ result: AuthorizeResult.ALLOW }));\n }\n\n async authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> {\n return (await this.isEnabled(options?.token))\n ? this.permissionClient.authorize(requests, options)\n : requests.map(_ => ({ result: AuthorizeResult.ALLOW }));\n }\n\n private async isValidServerToken(\n token: string | undefined,\n ): Promise<boolean> {\n if (!token) {\n return false;\n }\n return this.tokenManager\n .authenticate(token)\n .then(() => true)\n .catch(() => false);\n }\n\n private async isEnabled(token?: string) {\n // Check if permissions are enabled before validating the server token. That\n // way when permissions are disabled, the noop token manager can be used\n // without fouling up the logic inside the ServerPermissionClient, because\n // the code path won't be reached.\n return this.permissionEnabled && !(await this.isValidServerToken(token));\n }\n}\n"],"names":["AuthorizeResult","InputError","z","Router","express","zodToJsonSchema","NotImplementedError","errorHandler","PermissionClient"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/integration/createConditionFactory.ts","../src/integration/createConditionExports.ts","../src/integration/util.ts","../src/integration/createConditionTransformer.ts","../src/integration/createPermissionIntegrationRouter.ts","../src/integration/createPermissionRule.ts","../src/ServerPermissionClient.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PermissionCondition,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\n\n/**\n * Creates a condition factory function for a given authorization rule and parameter types.\n *\n * @remarks\n *\n * For example, an isEntityOwner rule for catalog entities might take an array of entityRef strings.\n * The rule itself defines _how_ to check a given resource, whereas a condition also includes _what_\n * to verify.\n *\n * Plugin authors should generally use the {@link createConditionExports} in order to efficiently\n * create multiple condition factories. This helper should generally only be used to construct\n * condition factories for third-party rules that aren't part of the backend plugin with which\n * they're intended to integrate.\n *\n * @public\n */\nexport const createConditionFactory = <\n TResourceType extends string,\n TParams extends PermissionRuleParams = PermissionRuleParams,\n>(\n rule: PermissionRule<unknown, unknown, TResourceType, TParams>,\n) => {\n return (params: TParams): PermissionCondition<TResourceType, TParams> => {\n return {\n rule: rule.name,\n resourceType: rule.resourceType,\n params,\n };\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthorizeResult,\n ConditionalPolicyDecision,\n PermissionCondition,\n PermissionCriteria,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport { createConditionFactory } from './createConditionFactory';\n\n/**\n * A utility type for mapping a single {@link PermissionRule} to its\n * corresponding {@link @backstage/plugin-permission-common#PermissionCondition}.\n *\n * @public\n */\nexport type Condition<TRule> = TRule extends PermissionRule<\n any,\n any,\n infer TResourceType,\n infer TParams\n>\n ? undefined extends TParams\n ? () => PermissionCondition<TResourceType, TParams>\n : (params: TParams) => PermissionCondition<TResourceType, TParams>\n : never;\n\n/**\n * A utility type for mapping {@link PermissionRule}s to their corresponding\n * {@link @backstage/plugin-permission-common#PermissionCondition}s.\n *\n * @public\n */\nexport type Conditions<\n TRules extends Record<string, PermissionRule<any, any, any>>,\n> = {\n [Name in keyof TRules]: Condition<TRules[Name]>;\n};\n\n/**\n * Creates the recommended condition-related exports for a given plugin based on\n * the built-in {@link PermissionRule}s it supports.\n *\n * @remarks\n *\n * The function returns a `conditions` object containing a\n * {@link @backstage/plugin-permission-common#PermissionCondition} factory for\n * each of the supplied {@link PermissionRule}s, along with a\n * `createConditionalDecision` function which builds the wrapper object needed\n * to enclose conditions when authoring {@link PermissionPolicy}\n * implementations.\n *\n * Plugin authors should generally call this method with all the built-in\n * {@link PermissionRule}s the plugin supports, and export the resulting\n * `conditions` object and `createConditionalDecision` function so that they can\n * be used by {@link PermissionPolicy} authors.\n *\n * @public\n */\nexport const createConditionExports = <\n TResourceType extends string,\n TResource,\n TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,\n>(options: {\n pluginId: string;\n resourceType: TResourceType;\n rules: TRules;\n}): {\n conditions: Conditions<TRules>;\n createConditionalDecision: (\n permission: ResourcePermission<TResourceType>,\n conditions: PermissionCriteria<PermissionCondition<TResourceType>>,\n ) => ConditionalPolicyDecision;\n} => {\n const { pluginId, resourceType, rules } = options;\n\n return {\n conditions: Object.entries(rules).reduce(\n (acc, [key, rule]) => ({\n ...acc,\n [key]: createConditionFactory(rule),\n }),\n {} as Conditions<TRules>,\n ),\n createConditionalDecision: (\n _permission: ResourcePermission<TResourceType>,\n conditions: PermissionCriteria<PermissionCondition>,\n ) => ({\n result: AuthorizeResult.CONDITIONAL,\n pluginId,\n resourceType,\n conditions,\n }),\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AllOfCriteria,\n AnyOfCriteria,\n NotCriteria,\n PermissionCriteria,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\n\n/**\n * Prevent use of type parameter from contributing to type inference.\n *\n * https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-980401795\n * @ignore\n */\nexport type NoInfer<T> = T extends infer S ? S : never;\n\n/**\n * Utility function used to parse a PermissionCriteria\n * @param criteria - a PermissionCriteria\n * @public\n *\n * @returns `true` if the permission criteria is of type allOf,\n * narrowing down `criteria` to the specific type.\n */\nexport const isAndCriteria = <T>(\n criteria: PermissionCriteria<T>,\n): criteria is AllOfCriteria<T> =>\n Object.prototype.hasOwnProperty.call(criteria, 'allOf');\n\n/**\n * Utility function used to parse a PermissionCriteria of type\n * @param criteria - a PermissionCriteria\n * @public\n *\n * @returns `true` if the permission criteria is of type anyOf,\n * narrowing down `criteria` to the specific type.\n */\nexport const isOrCriteria = <T>(\n criteria: PermissionCriteria<T>,\n): criteria is AnyOfCriteria<T> =>\n Object.prototype.hasOwnProperty.call(criteria, 'anyOf');\n\n/**\n * Utility function used to parse a PermissionCriteria\n * @param criteria - a PermissionCriteria\n * @public\n *\n * @returns `true` if the permission criteria is of type not,\n * narrowing down `criteria` to the specific type.\n */\nexport const isNotCriteria = <T>(\n criteria: PermissionCriteria<T>,\n): criteria is NotCriteria<T> =>\n Object.prototype.hasOwnProperty.call(criteria, 'not');\n\nexport const createGetRule = <TResource, TQuery>(\n rules: PermissionRule<TResource, TQuery, string>[],\n) => {\n const rulesMap = new Map(Object.values(rules).map(rule => [rule.name, rule]));\n\n return (name: string): PermissionRule<TResource, TQuery, string> => {\n const rule = rulesMap.get(name);\n\n if (!rule) {\n throw new Error(`Unexpected permission rule: ${name}`);\n }\n\n return rule;\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { InputError } from '@backstage/errors';\nimport {\n AllOfCriteria,\n AnyOfCriteria,\n PermissionCondition,\n PermissionCriteria,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport {\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\n\nconst mapConditions = <TQuery>(\n criteria: PermissionCriteria<PermissionCondition>,\n getRule: (name: string) => PermissionRule<unknown, TQuery, string>,\n): PermissionCriteria<TQuery> => {\n if (isAndCriteria(criteria)) {\n return {\n allOf: criteria.allOf.map(child => mapConditions(child, getRule)),\n } as AllOfCriteria<TQuery>;\n } else if (isOrCriteria(criteria)) {\n return {\n anyOf: criteria.anyOf.map(child => mapConditions(child, getRule)),\n } as AnyOfCriteria<TQuery>;\n } else if (isNotCriteria(criteria)) {\n return {\n not: mapConditions(criteria.not, getRule),\n };\n }\n\n const rule = getRule(criteria.rule);\n const result = rule.paramsSchema?.safeParse(criteria.params);\n\n if (result && !result.success) {\n throw new InputError(`Parameters to rule are invalid`, result.error);\n }\n\n return rule.toQuery(criteria.params ?? {});\n};\n\n/**\n * A function which accepts {@link @backstage/plugin-permission-common#PermissionCondition}s\n * logically grouped in a {@link @backstage/plugin-permission-common#PermissionCriteria}\n * object, and transforms the {@link @backstage/plugin-permission-common#PermissionCondition}s\n * into plugin specific query fragments while retaining the enclosing criteria shape.\n *\n * @public\n */\nexport type ConditionTransformer<TQuery> = (\n conditions: PermissionCriteria<PermissionCondition>,\n) => PermissionCriteria<TQuery>;\n\n/**\n * A higher-order helper function which accepts an array of\n * {@link PermissionRule}s, and returns a {@link ConditionTransformer}\n * which transforms input conditions into equivalent plugin-specific\n * query fragments using the supplied rules.\n *\n * @public\n */\nexport const createConditionTransformer = <\n TQuery,\n TRules extends PermissionRule<any, TQuery, string>[],\n>(\n permissionRules: [...TRules],\n): ConditionTransformer<TQuery> => {\n const getRule = createGetRule(permissionRules);\n\n return conditions => mapConditions(conditions, getRule);\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express, { Response } from 'express';\nimport Router from 'express-promise-router';\nimport { z } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { InputError } from '@backstage/errors';\nimport { errorHandler } from '@backstage/backend-common';\nimport {\n AuthorizeResult,\n DefinitivePolicyDecision,\n IdentifiedPermissionMessage,\n Permission,\n PermissionCondition,\n PermissionCriteria,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport {\n NoInfer,\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\nimport { NotImplementedError } from '@backstage/errors';\n\nconst permissionCriteriaSchema: z.ZodSchema<\n PermissionCriteria<PermissionCondition>\n> = z.lazy(() =>\n z.union([\n z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }),\n z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }),\n z.object({ not: permissionCriteriaSchema }),\n z.object({\n rule: z.string(),\n resourceType: z.string(),\n params: z.record(z.any()).optional(),\n }),\n ]),\n);\n\nconst applyConditionsRequestSchema = z.object({\n items: z.array(\n z.object({\n id: z.string(),\n resourceRef: z.string(),\n resourceType: z.string(),\n conditions: permissionCriteriaSchema,\n }),\n ),\n});\n\n/**\n * A request to load the referenced resource and apply conditions in order to\n * finalize a conditional authorization response.\n *\n * @public\n */\nexport type ApplyConditionsRequestEntry = IdentifiedPermissionMessage<{\n resourceRef: string;\n resourceType: string;\n conditions: PermissionCriteria<PermissionCondition>;\n}>;\n\n/**\n * A batch of {@link ApplyConditionsRequestEntry} objects.\n *\n * @public\n */\nexport type ApplyConditionsRequest = {\n items: ApplyConditionsRequestEntry[];\n};\n\n/**\n * The result of applying the conditions, expressed as a definitive authorize\n * result of ALLOW or DENY.\n *\n * @public\n */\nexport type ApplyConditionsResponseEntry =\n IdentifiedPermissionMessage<DefinitivePolicyDecision>;\n\n/**\n * A batch of {@link ApplyConditionsResponseEntry} objects.\n *\n * @public\n */\nexport type ApplyConditionsResponse = {\n items: ApplyConditionsResponseEntry[];\n};\n\n/**\n * Serialized permission rules, with the paramsSchema\n * converted from a ZodSchema to a JsonSchema.\n *\n * @public\n */\nexport type MetadataResponseSerializedRule = {\n name: string;\n description: string;\n resourceType: string;\n paramsSchema?: ReturnType<typeof zodToJsonSchema>;\n};\n\n/**\n * Response type for the .metadata endpoint.\n *\n * @public\n */\nexport type MetadataResponse = {\n permissions?: Permission[];\n rules: MetadataResponseSerializedRule[];\n};\n\nconst applyConditions = <TResourceType extends string, TResource>(\n criteria: PermissionCriteria<PermissionCondition<TResourceType>>,\n resource: TResource | undefined,\n getRule: (name: string) => PermissionRule<TResource, unknown, TResourceType>,\n): boolean => {\n // If resource was not found, deny. This avoids leaking information from the\n // apply-conditions API which would allow a user to differentiate between\n // non-existent resources and resources to which they do not have access.\n if (resource === undefined) {\n return false;\n }\n\n if (isAndCriteria(criteria)) {\n return criteria.allOf.every(child =>\n applyConditions(child, resource, getRule),\n );\n } else if (isOrCriteria(criteria)) {\n return criteria.anyOf.some(child =>\n applyConditions(child, resource, getRule),\n );\n } else if (isNotCriteria(criteria)) {\n return !applyConditions(criteria.not, resource, getRule);\n }\n\n const rule = getRule(criteria.rule);\n const result = rule.paramsSchema?.safeParse(criteria.params);\n\n if (result && !result.success) {\n throw new InputError(`Parameters to rule are invalid`, result.error);\n }\n\n return rule.apply(resource, criteria.params ?? {});\n};\n\n/**\n\n * Takes some permission conditions and returns a definitive authorization result\n * on the resource to which they apply.\n *\n * @public\n */\nexport const createConditionAuthorizer = <TResource, TQuery>(\n rules: PermissionRule<TResource, TQuery, string>[],\n) => {\n const getRule = createGetRule(rules);\n\n return (\n decision: PolicyDecision,\n resource: TResource | undefined,\n ): boolean => {\n if (decision.result === AuthorizeResult.CONDITIONAL) {\n return applyConditions(decision.conditions, resource, getRule);\n }\n\n return decision.result === AuthorizeResult.ALLOW;\n };\n};\n\n/**\n * Options for creating a permission integration router specific\n * for a particular resource type.\n *\n * @public\n */\nexport type CreatePermissionIntegrationRouterResourceOptions<\n TResourceType extends string,\n TResource,\n> = {\n resourceType: TResourceType;\n permissions?: Array<Permission>;\n // Do not infer value of TResourceType from supplied rules.\n // instead only consider the resourceType parameter, and\n // consider any rules whose resource type does not match\n // to be an error.\n rules: PermissionRule<TResource, any, NoInfer<TResourceType>>[];\n getResources?: (\n resourceRefs: string[],\n ) => Promise<Array<TResource | undefined>>;\n};\n\n/**\n * Create an express Router which provides an authorization route to allow\n * integration between the permission backend and other Backstage backend\n * plugins. Plugin owners that wish to support conditional authorization for\n * their resources should add the router created by this function to their\n * express app inside their `createRouter` implementation.\n *\n * In case the `permissions` option is provided, the router also\n * provides a route that exposes permissions and routes of a plugin.\n *\n * @remarks\n *\n * To make this concrete, we can use the Backstage software catalog as an\n * example. The catalog has conditional rules around access to specific\n * _entities_ in the catalog. The _type_ of resource is captured here as\n * `resourceType`, a string identifier (`catalog-entity` in this example) that\n * can be provided with permission definitions. This is merely a _type_ to\n * verify that conditions in an authorization policy are constructed correctly,\n * not a reference to a specific resource.\n *\n * The `rules` parameter is an array of {@link PermissionRule}s that introduce\n * conditional filtering logic for resources; for the catalog, these are things\n * like `isEntityOwner` or `hasAnnotation`. Rules describe how to filter a list\n * of resources, and the `conditions` returned allow these rules to be applied\n * with specific parameters (such as 'group:default/team-a', or\n * 'backstage.io/edit-url').\n *\n * The `getResources` argument should load resources based on a reference\n * identifier. For the catalog, this is an\n * {@link @backstage/catalog-model#EntityRef}. For other plugins, this can be\n * any serialized format. This is used to construct the\n * `createPermissionIntegrationRouter`, a function to add an authorization route\n * to your backend plugin. This function will be called by the\n * `permission-backend` when authorization conditions relating to this plugin\n * need to be evaluated.\n *\n * @public\n */\nexport function createPermissionIntegrationRouter<\n TResourceType extends string,\n TResource,\n>(\n options: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n): express.Router;\n\n/**\n *\n * Create an express Router which provides a route that exposes\n * permissions and routes of a plugin.\n * @public\n */\nexport function createPermissionIntegrationRouter(options: {\n permissions: Array<Permission>;\n}): express.Router;\n\n/**\n * @public\n */\nexport function createPermissionIntegrationRouter<\n TResourceType extends string,\n TResource,\n>(\n options:\n | { permissions: Array<Permission> }\n | CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n): express.Router {\n const router = Router();\n router.use(express.json());\n\n const { permissions = [], rules = [] } = { rules: [], ...options };\n router.get('/.well-known/backstage/permissions/metadata', (_, res) => {\n const serializedRules: MetadataResponseSerializedRule[] = rules.map(\n rule => ({\n name: rule.name,\n description: rule.description,\n resourceType: rule.resourceType,\n paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})),\n }),\n );\n\n const responseJson: MetadataResponse = {\n permissions,\n rules: serializedRules,\n };\n\n return res.json(responseJson);\n });\n\n router.post(\n '/.well-known/backstage/permissions/apply-conditions',\n async (req, res: Response<ApplyConditionsResponse | string>) => {\n if (\n !isCreatePermissionIntegrationRouterResourceOptions(options) ||\n options.getResources === undefined\n ) {\n throw new NotImplementedError(\n `This plugin does not expose any permission rule or can't evaluate conditional decisions`,\n );\n }\n const { resourceType, getResources } = options;\n\n const getRule = createGetRule(rules);\n\n const assertValidResourceTypes = (\n requests: ApplyConditionsRequestEntry[],\n ) => {\n const invalidResourceTypes = requests\n .filter(request => request.resourceType !== resourceType)\n .map(request => request.resourceType);\n\n if (invalidResourceTypes.length) {\n throw new InputError(\n `Unexpected resource types: ${invalidResourceTypes.join(', ')}.`,\n );\n }\n };\n\n const parseResult = applyConditionsRequestSchema.safeParse(req.body);\n\n if (!parseResult.success) {\n throw new InputError(parseResult.error.toString());\n }\n\n const body = parseResult.data;\n\n assertValidResourceTypes(body.items);\n\n const resourceRefs = Array.from(\n new Set(body.items.map(({ resourceRef }) => resourceRef)),\n );\n const resourceArray = await getResources(resourceRefs);\n const resources = resourceRefs.reduce((acc, resourceRef, index) => {\n acc[resourceRef] = resourceArray[index];\n\n return acc;\n }, {} as Record<string, TResource | undefined>);\n\n return res.json({\n items: body.items.map(request => ({\n id: request.id,\n result: applyConditions(\n request.conditions,\n resources[request.resourceRef],\n getRule,\n )\n ? AuthorizeResult.ALLOW\n : AuthorizeResult.DENY,\n })),\n });\n },\n );\n\n router.use(errorHandler());\n\n return router;\n}\n\nfunction isCreatePermissionIntegrationRouterResourceOptions<\n TResourceType extends string,\n TResource,\n>(\n options:\n | { permissions: Array<Permission> }\n | CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n): options is CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n> {\n return (\n (\n options as CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >\n ).resourceType !== undefined\n );\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\n\n/**\n * Helper function to ensure that {@link PermissionRule} definitions are typed correctly.\n *\n * @public\n */\nexport const createPermissionRule = <\n TResource,\n TQuery,\n TResourceType extends string,\n TParams extends PermissionRuleParams = undefined,\n>(\n rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,\n) => rule;\n\n/**\n * Helper for making plugin-specific createPermissionRule functions, that have\n * the TResource and TQuery type parameters populated but infer the params from\n * the supplied rule. This helps ensure that rules created for this plugin use\n * consistent types for the resource and query.\n *\n * @public\n */\nexport const makeCreatePermissionRule =\n <TResource, TQuery, TResourceType extends string>() =>\n <TParams extends PermissionRuleParams = undefined>(\n rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,\n ) =>\n createPermissionRule(rule);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n TokenManager,\n PluginEndpointDiscovery,\n} from '@backstage/backend-common';\nimport { Config } from '@backstage/config';\nimport {\n AuthorizeResult,\n PermissionClient,\n PermissionEvaluator,\n AuthorizePermissionRequest,\n EvaluatorRequestOptions,\n AuthorizePermissionResponse,\n PolicyDecision,\n QueryPermissionRequest,\n} from '@backstage/plugin-permission-common';\n\n/**\n * A thin wrapper around\n * {@link @backstage/plugin-permission-common#PermissionClient} that allows all\n * service-to-service requests.\n * @public\n */\nexport class ServerPermissionClient implements PermissionEvaluator {\n private readonly permissionClient: PermissionClient;\n private readonly tokenManager: TokenManager;\n private readonly permissionEnabled: boolean;\n\n static fromConfig(\n config: Config,\n options: {\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n },\n ) {\n const { discovery, tokenManager } = options;\n const permissionClient = new PermissionClient({ discovery, config });\n const permissionEnabled =\n config.getOptionalBoolean('permission.enabled') ?? false;\n\n if (\n permissionEnabled &&\n (tokenManager as any).isInsecureServerTokenManager\n ) {\n throw new Error(\n 'Service-to-service authentication must be configured before enabling permissions. Read more here https://backstage.io/docs/auth/service-to-service-auth',\n );\n }\n\n return new ServerPermissionClient({\n permissionClient,\n tokenManager,\n permissionEnabled,\n });\n }\n\n private constructor(options: {\n permissionClient: PermissionClient;\n tokenManager: TokenManager;\n permissionEnabled: boolean;\n }) {\n this.permissionClient = options.permissionClient;\n this.tokenManager = options.tokenManager;\n this.permissionEnabled = options.permissionEnabled;\n }\n\n async authorizeConditional(\n queries: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<PolicyDecision[]> {\n return (await this.isEnabled(options?.token))\n ? this.permissionClient.authorizeConditional(queries, options)\n : queries.map(_ => ({ result: AuthorizeResult.ALLOW }));\n }\n\n async authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> {\n return (await this.isEnabled(options?.token))\n ? this.permissionClient.authorize(requests, options)\n : requests.map(_ => ({ result: AuthorizeResult.ALLOW }));\n }\n\n private async isValidServerToken(\n token: string | undefined,\n ): Promise<boolean> {\n if (!token) {\n return false;\n }\n return this.tokenManager\n .authenticate(token)\n .then(() => true)\n .catch(() => false);\n }\n\n private async isEnabled(token?: string) {\n // Check if permissions are enabled before validating the server token. That\n // way when permissions are disabled, the noop token manager can be used\n // without fouling up the logic inside the ServerPermissionClient, because\n // the code path won't be reached.\n return this.permissionEnabled && !(await this.isValidServerToken(token));\n }\n}\n"],"names":["AuthorizeResult","InputError","z","Router","express","zodToJsonSchema","NotImplementedError","errorHandler","PermissionClient"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as _backstage_plugin_permission_common from '@backstage/plugin-permission-common';
|
|
2
1
|
import { PermissionCriteria, AllOfCriteria, AnyOfCriteria, NotCriteria, PermissionRuleParams, PermissionCondition, ResourcePermission, ConditionalPolicyDecision, IdentifiedPermissionMessage, DefinitivePolicyDecision, Permission, PolicyDecision, PermissionEvaluator, QueryPermissionRequest, EvaluatorRequestOptions, AuthorizePermissionRequest, AuthorizePermissionResponse } from '@backstage/plugin-permission-common';
|
|
3
2
|
import { z } from 'zod';
|
|
4
3
|
import express from 'express';
|
|
@@ -13,7 +12,7 @@ import { Config } from '@backstage/config';
|
|
|
13
12
|
* https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-980401795
|
|
14
13
|
* @ignore
|
|
15
14
|
*/
|
|
16
|
-
|
|
15
|
+
type NoInfer<T> = T extends infer S ? S : never;
|
|
17
16
|
/**
|
|
18
17
|
* Utility function used to parse a PermissionCriteria
|
|
19
18
|
* @param criteria - a PermissionCriteria
|
|
@@ -58,7 +57,7 @@ declare const isNotCriteria: <T>(criteria: PermissionCriteria<T>) => criteria is
|
|
|
58
57
|
*
|
|
59
58
|
* @public
|
|
60
59
|
*/
|
|
61
|
-
|
|
60
|
+
type PermissionRule<TResource, TQuery, TResourceType extends string, TParams extends PermissionRuleParams = PermissionRuleParams> = {
|
|
62
61
|
name: string;
|
|
63
62
|
description: string;
|
|
64
63
|
resourceType: TResourceType;
|
|
@@ -104,14 +103,14 @@ declare const createConditionFactory: <TResourceType extends string, TParams ext
|
|
|
104
103
|
*
|
|
105
104
|
* @public
|
|
106
105
|
*/
|
|
107
|
-
|
|
106
|
+
type Condition<TRule> = TRule extends PermissionRule<any, any, infer TResourceType, infer TParams> ? undefined extends TParams ? () => PermissionCondition<TResourceType, TParams> : (params: TParams) => PermissionCondition<TResourceType, TParams> : never;
|
|
108
107
|
/**
|
|
109
108
|
* A utility type for mapping {@link PermissionRule}s to their corresponding
|
|
110
109
|
* {@link @backstage/plugin-permission-common#PermissionCondition}s.
|
|
111
110
|
*
|
|
112
111
|
* @public
|
|
113
112
|
*/
|
|
114
|
-
|
|
113
|
+
type Conditions<TRules extends Record<string, PermissionRule<any, any, any>>> = {
|
|
115
114
|
[Name in keyof TRules]: Condition<TRules[Name]>;
|
|
116
115
|
};
|
|
117
116
|
/**
|
|
@@ -134,13 +133,13 @@ declare type Conditions<TRules extends Record<string, PermissionRule<any, any, a
|
|
|
134
133
|
*
|
|
135
134
|
* @public
|
|
136
135
|
*/
|
|
137
|
-
declare const createConditionExports: <TResourceType extends string, TResource, TRules extends Record<string, PermissionRule<TResource, any, TResourceType
|
|
136
|
+
declare const createConditionExports: <TResourceType extends string, TResource, TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>>(options: {
|
|
138
137
|
pluginId: string;
|
|
139
138
|
resourceType: TResourceType;
|
|
140
139
|
rules: TRules;
|
|
141
140
|
}) => {
|
|
142
141
|
conditions: Conditions<TRules>;
|
|
143
|
-
createConditionalDecision: (permission: ResourcePermission<TResourceType>, conditions: PermissionCriteria<PermissionCondition<TResourceType
|
|
142
|
+
createConditionalDecision: (permission: ResourcePermission<TResourceType>, conditions: PermissionCriteria<PermissionCondition<TResourceType>>) => ConditionalPolicyDecision;
|
|
144
143
|
};
|
|
145
144
|
|
|
146
145
|
/**
|
|
@@ -151,7 +150,7 @@ declare const createConditionExports: <TResourceType extends string, TResource,
|
|
|
151
150
|
*
|
|
152
151
|
* @public
|
|
153
152
|
*/
|
|
154
|
-
|
|
153
|
+
type ConditionTransformer<TQuery> = (conditions: PermissionCriteria<PermissionCondition>) => PermissionCriteria<TQuery>;
|
|
155
154
|
/**
|
|
156
155
|
* A higher-order helper function which accepts an array of
|
|
157
156
|
* {@link PermissionRule}s, and returns a {@link ConditionTransformer}
|
|
@@ -160,7 +159,7 @@ declare type ConditionTransformer<TQuery> = (conditions: PermissionCriteria<Perm
|
|
|
160
159
|
*
|
|
161
160
|
* @public
|
|
162
161
|
*/
|
|
163
|
-
declare const createConditionTransformer: <TQuery, TRules extends PermissionRule<any, TQuery, string
|
|
162
|
+
declare const createConditionTransformer: <TQuery, TRules extends PermissionRule<any, TQuery, string>[]>(permissionRules: [...TRules]) => ConditionTransformer<TQuery>;
|
|
164
163
|
|
|
165
164
|
/**
|
|
166
165
|
* A request to load the referenced resource and apply conditions in order to
|
|
@@ -168,7 +167,7 @@ declare const createConditionTransformer: <TQuery, TRules extends PermissionRule
|
|
|
168
167
|
*
|
|
169
168
|
* @public
|
|
170
169
|
*/
|
|
171
|
-
|
|
170
|
+
type ApplyConditionsRequestEntry = IdentifiedPermissionMessage<{
|
|
172
171
|
resourceRef: string;
|
|
173
172
|
resourceType: string;
|
|
174
173
|
conditions: PermissionCriteria<PermissionCondition>;
|
|
@@ -178,7 +177,7 @@ declare type ApplyConditionsRequestEntry = IdentifiedPermissionMessage<{
|
|
|
178
177
|
*
|
|
179
178
|
* @public
|
|
180
179
|
*/
|
|
181
|
-
|
|
180
|
+
type ApplyConditionsRequest = {
|
|
182
181
|
items: ApplyConditionsRequestEntry[];
|
|
183
182
|
};
|
|
184
183
|
/**
|
|
@@ -187,13 +186,13 @@ declare type ApplyConditionsRequest = {
|
|
|
187
186
|
*
|
|
188
187
|
* @public
|
|
189
188
|
*/
|
|
190
|
-
|
|
189
|
+
type ApplyConditionsResponseEntry = IdentifiedPermissionMessage<DefinitivePolicyDecision>;
|
|
191
190
|
/**
|
|
192
191
|
* A batch of {@link ApplyConditionsResponseEntry} objects.
|
|
193
192
|
*
|
|
194
193
|
* @public
|
|
195
194
|
*/
|
|
196
|
-
|
|
195
|
+
type ApplyConditionsResponse = {
|
|
197
196
|
items: ApplyConditionsResponseEntry[];
|
|
198
197
|
};
|
|
199
198
|
/**
|
|
@@ -202,7 +201,7 @@ declare type ApplyConditionsResponse = {
|
|
|
202
201
|
*
|
|
203
202
|
* @public
|
|
204
203
|
*/
|
|
205
|
-
|
|
204
|
+
type MetadataResponseSerializedRule = {
|
|
206
205
|
name: string;
|
|
207
206
|
description: string;
|
|
208
207
|
resourceType: string;
|
|
@@ -213,17 +212,25 @@ declare type MetadataResponseSerializedRule = {
|
|
|
213
212
|
*
|
|
214
213
|
* @public
|
|
215
214
|
*/
|
|
216
|
-
|
|
215
|
+
type MetadataResponse = {
|
|
217
216
|
permissions?: Permission[];
|
|
218
217
|
rules: MetadataResponseSerializedRule[];
|
|
219
218
|
};
|
|
219
|
+
/**
|
|
220
|
+
|
|
221
|
+
* Takes some permission conditions and returns a definitive authorization result
|
|
222
|
+
* on the resource to which they apply.
|
|
223
|
+
*
|
|
224
|
+
* @public
|
|
225
|
+
*/
|
|
226
|
+
declare const createConditionAuthorizer: <TResource, TQuery>(rules: PermissionRule<TResource, TQuery, string>[]) => (decision: PolicyDecision, resource: TResource | undefined) => boolean;
|
|
220
227
|
/**
|
|
221
228
|
* Options for creating a permission integration router specific
|
|
222
229
|
* for a particular resource type.
|
|
223
230
|
*
|
|
224
231
|
* @public
|
|
225
232
|
*/
|
|
226
|
-
|
|
233
|
+
type CreatePermissionIntegrationRouterResourceOptions<TResourceType extends string, TResource> = {
|
|
227
234
|
resourceType: TResourceType;
|
|
228
235
|
permissions?: Array<Permission>;
|
|
229
236
|
rules: PermissionRule<TResource, any, NoInfer<TResourceType>>[];
|
|
@@ -304,7 +311,7 @@ declare const makeCreatePermissionRule: <TResource, TQuery, TResourceType extend
|
|
|
304
311
|
*
|
|
305
312
|
* @public
|
|
306
313
|
*/
|
|
307
|
-
|
|
314
|
+
type PolicyQuery = {
|
|
308
315
|
permission: Permission;
|
|
309
316
|
};
|
|
310
317
|
/**
|
|
@@ -348,4 +355,4 @@ declare class ServerPermissionClient implements PermissionEvaluator {
|
|
|
348
355
|
private isEnabled;
|
|
349
356
|
}
|
|
350
357
|
|
|
351
|
-
export { ApplyConditionsRequest, ApplyConditionsRequestEntry, ApplyConditionsResponse, ApplyConditionsResponseEntry, Condition, ConditionTransformer, Conditions, CreatePermissionIntegrationRouterResourceOptions, MetadataResponse, MetadataResponseSerializedRule, PermissionPolicy, PermissionRule, PolicyQuery, ServerPermissionClient, createConditionExports, createConditionFactory, createConditionTransformer, createPermissionIntegrationRouter, createPermissionRule, isAndCriteria, isNotCriteria, isOrCriteria, makeCreatePermissionRule };
|
|
358
|
+
export { ApplyConditionsRequest, ApplyConditionsRequestEntry, ApplyConditionsResponse, ApplyConditionsResponseEntry, Condition, ConditionTransformer, Conditions, CreatePermissionIntegrationRouterResourceOptions, MetadataResponse, MetadataResponseSerializedRule, PermissionPolicy, PermissionRule, PolicyQuery, ServerPermissionClient, createConditionAuthorizer, createConditionExports, createConditionFactory, createConditionTransformer, createPermissionIntegrationRouter, createPermissionRule, isAndCriteria, isNotCriteria, isOrCriteria, makeCreatePermissionRule };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-permission-node",
|
|
3
3
|
"description": "Common permission and authorization utilities for backend plugins",
|
|
4
|
-
"version": "0.7.7-next.
|
|
4
|
+
"version": "0.7.7-next.2",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -10,6 +10,19 @@
|
|
|
10
10
|
"main": "dist/index.cjs.js",
|
|
11
11
|
"types": "dist/index.d.ts"
|
|
12
12
|
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"require": "./dist/index.cjs.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.cjs.js"
|
|
18
|
+
},
|
|
19
|
+
"./alpha": {
|
|
20
|
+
"require": "./dist/alpha.cjs.js",
|
|
21
|
+
"types": "./dist/alpha.d.ts",
|
|
22
|
+
"default": "./dist/alpha.cjs.js"
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
13
26
|
"backstage": {
|
|
14
27
|
"role": "node-library"
|
|
15
28
|
},
|
|
@@ -33,25 +46,27 @@
|
|
|
33
46
|
"start": "backstage-cli package start"
|
|
34
47
|
},
|
|
35
48
|
"dependencies": {
|
|
36
|
-
"@backstage/backend-common": "^0.18.4-next.
|
|
49
|
+
"@backstage/backend-common": "^0.18.4-next.2",
|
|
50
|
+
"@backstage/backend-plugin-api": "^0.5.1-next.2",
|
|
37
51
|
"@backstage/config": "^1.0.7",
|
|
38
52
|
"@backstage/errors": "^1.1.5",
|
|
39
|
-
"@backstage/plugin-auth-node": "^0.2.13-next.
|
|
40
|
-
"@backstage/plugin-permission-common": "^0.7.
|
|
53
|
+
"@backstage/plugin-auth-node": "^0.2.13-next.2",
|
|
54
|
+
"@backstage/plugin-permission-common": "^0.7.5-next.0",
|
|
41
55
|
"@types/express": "^4.17.6",
|
|
42
56
|
"express": "^4.17.1",
|
|
43
57
|
"express-promise-router": "^4.1.0",
|
|
44
|
-
"zod": "
|
|
45
|
-
"zod-to-json-schema": "
|
|
58
|
+
"zod": "^3.21.4",
|
|
59
|
+
"zod-to-json-schema": "^3.20.4"
|
|
46
60
|
},
|
|
47
61
|
"devDependencies": {
|
|
48
|
-
"@backstage/backend-test-utils": "^0.1.36-next.
|
|
49
|
-
"@backstage/cli": "^0.22.6-next.
|
|
62
|
+
"@backstage/backend-test-utils": "^0.1.36-next.2",
|
|
63
|
+
"@backstage/cli": "^0.22.6-next.2",
|
|
50
64
|
"@types/supertest": "^2.0.8",
|
|
51
65
|
"msw": "^1.0.0",
|
|
52
66
|
"supertest": "^6.1.3"
|
|
53
67
|
},
|
|
54
68
|
"files": [
|
|
55
|
-
"dist"
|
|
69
|
+
"dist",
|
|
70
|
+
"alpha"
|
|
56
71
|
]
|
|
57
72
|
}
|