@backstage/plugin-permission-node 0.11.3-next.0 → 0.11.4-next.0
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 +17 -0
- package/dist/index.d.ts +30 -7
- package/dist/integration/createConditionTransformer.cjs.js +2 -5
- package/dist/integration/createConditionTransformer.cjs.js.map +1 -1
- package/dist/integration/createPermissionIntegrationRouter.cjs.js +4 -7
- package/dist/integration/createPermissionIntegrationRouter.cjs.js.map +1 -1
- package/dist/integration/createPermissionRule.cjs.js +3 -0
- package/dist/integration/createPermissionRule.cjs.js.map +1 -1
- package/dist/integration/permissionRuleParams.cjs.js +68 -0
- package/dist/integration/permissionRuleParams.cjs.js.map +1 -0
- package/dist/packages/backend-internal/src/wiring/OpaqueExtensionPointFactoryMiddleware.cjs.js +9 -0
- package/dist/packages/backend-internal/src/wiring/OpaqueExtensionPointFactoryMiddleware.cjs.js.map +1 -0
- package/dist/packages/backend-internal/src/wiring/helpers.cjs.js +8 -0
- package/dist/packages/backend-internal/src/wiring/helpers.cjs.js.map +1 -0
- package/dist/packages/opaque-internal/src/OpaqueType.cjs.js +105 -0
- package/dist/packages/opaque-internal/src/OpaqueType.cjs.js.map +1 -0
- package/package.json +8 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @backstage/plugin-permission-node
|
|
2
2
|
|
|
3
|
+
## 0.11.4-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/backend-plugin-api@1.10.1-next.0
|
|
9
|
+
|
|
10
|
+
## 0.11.3
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- b754e32: Migrated tests from MSW v1 to MSW v2.
|
|
15
|
+
- 2c99b29: Permission rule parameter schemas now accept JSON Schema-compatible Standard Schema implementations, such as Zod v4. Zod v3 schemas remain supported but are deprecated.
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @backstage/backend-plugin-api@1.10.0
|
|
18
|
+
- @backstage/plugin-permission-common@0.9.10
|
|
19
|
+
|
|
3
20
|
## 0.11.3-next.0
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PermissionRuleParams, PermissionCriteria, PermissionCondition, ResourcePermission, ConditionalPolicyDecision, IdentifiedPermissionMessage, DefinitivePolicyDecision, AuthorizeResult, Permission, MetadataResponse as MetadataResponse$1, MetadataResponseSerializedRule as MetadataResponseSerializedRule$1, PolicyDecision, AllOfCriteria, NotCriteria, AnyOfCriteria, QueryPermissionRequest, AuthorizePermissionRequest, AuthorizePermissionResponse } from '@backstage/plugin-permission-common';
|
|
2
|
+
import { StandardSchemaV1, StandardJSONSchemaV1 } from '@standard-schema/spec';
|
|
2
3
|
import { z } from 'zod/v3';
|
|
3
4
|
import express from 'express';
|
|
4
5
|
import { BackstageCredentials, BackstageUserInfo, PermissionsService, DiscoveryService, AuthService, PermissionsServiceRequestOptions } from '@backstage/backend-plugin-api';
|
|
@@ -32,10 +33,6 @@ type PermissionRule<TResource, TQuery, TResourceType extends string, TParams ext
|
|
|
32
33
|
name: string;
|
|
33
34
|
description: string;
|
|
34
35
|
resourceType: TResourceType;
|
|
35
|
-
/**
|
|
36
|
-
* A ZodSchema that reflects the structure of the parameters that are passed to
|
|
37
|
-
*/
|
|
38
|
-
paramsSchema?: z.ZodSchema<TParams>;
|
|
39
36
|
/**
|
|
40
37
|
* Apply this rule to a resource already loaded from a backing data source. The params are
|
|
41
38
|
* arguments supplied for the rule; for example, a rule could be `isOwner` with entityRefs as the
|
|
@@ -48,7 +45,20 @@ type PermissionRule<TResource, TQuery, TResourceType extends string, TParams ext
|
|
|
48
45
|
* applied.
|
|
49
46
|
*/
|
|
50
47
|
toQuery(params: NoInfer<TParams>): PermissionCriteria<TQuery>;
|
|
51
|
-
}
|
|
48
|
+
} & ({
|
|
49
|
+
/**
|
|
50
|
+
* A Standard Schema that reflects the structure of the parameters that are passed to the rule.
|
|
51
|
+
* The schema must validate synchronously and support JSON Schema conversion.
|
|
52
|
+
*/
|
|
53
|
+
paramsSchema?: StandardSchemaV1<TParams> & StandardJSONSchemaV1<TParams>;
|
|
54
|
+
} | {
|
|
55
|
+
/**
|
|
56
|
+
* A ZodSchema that reflects the structure of the parameters that are passed to the rule.
|
|
57
|
+
*
|
|
58
|
+
* @deprecated Zod v3 is deprecated, switch to a JSON Schema-compatible Standard Schema instead, such as Zod v4.
|
|
59
|
+
*/
|
|
60
|
+
paramsSchema: z.ZodSchema<TParams>;
|
|
61
|
+
});
|
|
52
62
|
/**
|
|
53
63
|
* A set of registered rules for a particular resource type.
|
|
54
64
|
*
|
|
@@ -341,9 +351,10 @@ type CreatePermissionRuleOptions<TRef extends PermissionResourceRef, TParams ext
|
|
|
341
351
|
description: string;
|
|
342
352
|
resourceRef: TRef;
|
|
343
353
|
/**
|
|
344
|
-
* A
|
|
354
|
+
* A Standard Schema that reflects the structure of the parameters that are passed to the rule.
|
|
355
|
+
* The schema must validate synchronously and support JSON Schema conversion.
|
|
345
356
|
*/
|
|
346
|
-
paramsSchema?:
|
|
357
|
+
paramsSchema?: StandardSchemaV1<TParams> & StandardJSONSchemaV1<TParams>;
|
|
347
358
|
/**
|
|
348
359
|
* Apply this rule to a resource already loaded from a backing data source. The params are
|
|
349
360
|
* arguments supplied for the rule; for example, a rule could be `isOwner` with entityRefs as the
|
|
@@ -363,6 +374,18 @@ type CreatePermissionRuleOptions<TRef extends PermissionResourceRef, TParams ext
|
|
|
363
374
|
* @public
|
|
364
375
|
*/
|
|
365
376
|
declare function createPermissionRule<TRef extends PermissionResourceRef, TParams extends PermissionRuleParams = undefined>(rule: CreatePermissionRuleOptions<TRef, TParams>): PermissionRule<TRef['TResource'], TRef['TQuery'], TRef['resourceType'], TParams>;
|
|
377
|
+
/**
|
|
378
|
+
* @public
|
|
379
|
+
* @deprecated Zod v3 parameter schemas are deprecated, switch to a JSON Schema-compatible Standard Schema instead, such as Zod v4.
|
|
380
|
+
*/
|
|
381
|
+
declare function createPermissionRule<TRef extends PermissionResourceRef, TParams extends PermissionRuleParams = undefined>(rule: {
|
|
382
|
+
name: string;
|
|
383
|
+
description: string;
|
|
384
|
+
resourceRef: TRef;
|
|
385
|
+
paramsSchema: z.ZodSchema<TParams>;
|
|
386
|
+
apply(resource: TRef['TResource'], params: NoInfer<TParams>): boolean;
|
|
387
|
+
toQuery(params: NoInfer<TParams>): PermissionCriteria<TRef['TQuery']>;
|
|
388
|
+
}): PermissionRule<TRef['TResource'], TRef['TQuery'], TRef['resourceType'], TParams>;
|
|
366
389
|
/**
|
|
367
390
|
* Helper function to ensure that {@link PermissionRule} definitions are typed correctly.
|
|
368
391
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var errors = require('@backstage/errors');
|
|
4
3
|
var util = require('./util.cjs.js');
|
|
4
|
+
var permissionRuleParams = require('./permissionRuleParams.cjs.js');
|
|
5
5
|
|
|
6
6
|
const mapConditions = (criteria, getRule) => {
|
|
7
7
|
if (util.isAndCriteria(criteria)) {
|
|
@@ -18,10 +18,7 @@ const mapConditions = (criteria, getRule) => {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
const rule = getRule(criteria.rule);
|
|
21
|
-
|
|
22
|
-
if (result && !result.success) {
|
|
23
|
-
throw new errors.InputError(`Parameters to rule are invalid`, result.error);
|
|
24
|
-
}
|
|
21
|
+
permissionRuleParams.validatePermissionRuleParams(rule, criteria.params);
|
|
25
22
|
return rule.toQuery(criteria.params ?? {});
|
|
26
23
|
};
|
|
27
24
|
function createConditionTransformer(permissionRules) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createConditionTransformer.cjs.js","sources":["../../src/integration/createConditionTransformer.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 */\nimport {
|
|
1
|
+
{"version":3,"file":"createConditionTransformer.cjs.js","sources":["../../src/integration/createConditionTransformer.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 */\nimport {\n AllOfCriteria,\n AnyOfCriteria,\n PermissionCondition,\n PermissionCriteria,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule, PermissionRuleset } from '../types';\nimport {\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\nimport { validatePermissionRuleParams } from './permissionRuleParams';\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 validatePermissionRuleParams(rule, criteria.params);\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 function createConditionTransformer<TQuery>(\n permissionRuleset: PermissionRuleset<any, TQuery>,\n): ConditionTransformer<TQuery>;\n/**\n * @public\n * @deprecated Use the version of `createConditionTransformer` that accepts a `PermissionRuleset` instead.\n */\nexport function createConditionTransformer<\n TQuery,\n TRules extends PermissionRule<any, TQuery, string>[],\n>(permissionRules: [...TRules]): ConditionTransformer<TQuery>;\nexport function createConditionTransformer<TQuery>(\n permissionRules:\n | PermissionRule<any, TQuery, string>[]\n | PermissionRuleset<any, TQuery>,\n): ConditionTransformer<TQuery> {\n const getRule =\n 'getRuleByName' in permissionRules\n ? (n: string) => permissionRules.getRuleByName(n)\n : createGetRule(permissionRules);\n\n return conditions => mapConditions(conditions, getRule);\n}\n"],"names":["isAndCriteria","isOrCriteria","isNotCriteria","validatePermissionRuleParams","createGetRule"],"mappings":";;;;;AA8BA,MAAM,aAAA,GAAgB,CACpB,QAAA,EACA,OAAA,KAC+B;AAC/B,EAAA,IAAIA,kBAAA,CAAc,QAAQ,CAAA,EAAG;AAC3B,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,SAAS,KAAA,CAAM,GAAA,CAAI,WAAS,aAAA,CAAc,KAAA,EAAO,OAAO,CAAC;AAAA,KAClE;AAAA,EACF,CAAA,MAAA,IAAWC,iBAAA,CAAa,QAAQ,CAAA,EAAG;AACjC,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,SAAS,KAAA,CAAM,GAAA,CAAI,WAAS,aAAA,CAAc,KAAA,EAAO,OAAO,CAAC;AAAA,KAClE;AAAA,EACF,CAAA,MAAA,IAAWC,kBAAA,CAAc,QAAQ,CAAA,EAAG;AAClC,IAAA,OAAO;AAAA,MACL,GAAA,EAAK,aAAA,CAAc,QAAA,CAAS,GAAA,EAAK,OAAO;AAAA,KAC1C;AAAA,EACF;AAEA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA;AAClC,EAAAC,iDAAA,CAA6B,IAAA,EAAM,SAAS,MAAM,CAAA;AAElD,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,QAAA,CAAS,MAAA,IAAU,EAAE,CAAA;AAC3C,CAAA;AAiCO,SAAS,2BACd,eAAA,EAG8B;AAC9B,EAAA,MAAM,OAAA,GACJ,eAAA,IAAmB,eAAA,GACf,CAAC,CAAA,KAAc,gBAAgB,aAAA,CAAc,CAAC,CAAA,GAC9CC,kBAAA,CAAc,eAAe,CAAA;AAEnC,EAAA,OAAO,CAAA,UAAA,KAAc,aAAA,CAAc,UAAA,EAAY,OAAO,CAAA;AACxD;;;;"}
|
|
@@ -3,16 +3,15 @@
|
|
|
3
3
|
var express = require('express');
|
|
4
4
|
var Router = require('express-promise-router');
|
|
5
5
|
var v3 = require('zod/v3');
|
|
6
|
-
var zodToJsonSchema = require('zod-to-json-schema');
|
|
7
6
|
var errors = require('@backstage/errors');
|
|
8
7
|
var pluginPermissionCommon = require('@backstage/plugin-permission-common');
|
|
9
8
|
var util = require('./util.cjs.js');
|
|
9
|
+
var permissionRuleParams = require('./permissionRuleParams.cjs.js');
|
|
10
10
|
|
|
11
11
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
12
12
|
|
|
13
13
|
var express__default = /*#__PURE__*/_interopDefaultCompat(express);
|
|
14
14
|
var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
|
|
15
|
-
var zodToJsonSchema__default = /*#__PURE__*/_interopDefaultCompat(zodToJsonSchema);
|
|
16
15
|
|
|
17
16
|
const permissionCriteriaSchema = v3.z.lazy(
|
|
18
17
|
() => v3.z.union([
|
|
@@ -52,10 +51,7 @@ const applyConditions = (criteria, resource, getRule) => {
|
|
|
52
51
|
return !applyConditions(criteria.not, resource, getRule);
|
|
53
52
|
}
|
|
54
53
|
const rule = getRule(criteria.rule);
|
|
55
|
-
|
|
56
|
-
if (result && !result.success) {
|
|
57
|
-
throw new errors.InputError(`Parameters to rule are invalid`, result.error);
|
|
58
|
-
}
|
|
54
|
+
permissionRuleParams.validatePermissionRuleParams(rule, criteria.params);
|
|
59
55
|
return rule.apply(resource, criteria.params ?? {});
|
|
60
56
|
};
|
|
61
57
|
function authorizeResult(criteria, resource, getRule) {
|
|
@@ -115,6 +111,7 @@ class PermissionIntegrationMetadataStore {
|
|
|
115
111
|
}
|
|
116
112
|
addPermissionRules(rules) {
|
|
117
113
|
for (const rule of rules) {
|
|
114
|
+
permissionRuleParams.assertPermissionRuleParamsSchema(rule);
|
|
118
115
|
const rulesByName = this.#rulesByTypeByName.get(rule.resourceType) ?? /* @__PURE__ */ new Map();
|
|
119
116
|
this.#rulesByTypeByName.set(rule.resourceType, rulesByName);
|
|
120
117
|
if (rulesByName.has(rule.name)) {
|
|
@@ -127,7 +124,7 @@ class PermissionIntegrationMetadataStore {
|
|
|
127
124
|
name: rule.name,
|
|
128
125
|
description: rule.description,
|
|
129
126
|
resourceType: rule.resourceType,
|
|
130
|
-
paramsSchema:
|
|
127
|
+
paramsSchema: permissionRuleParams.permissionRuleParamsToJsonSchema(rule)
|
|
131
128
|
});
|
|
132
129
|
}
|
|
133
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPermissionIntegrationRouter.cjs.js","sources":["../../src/integration/createPermissionIntegrationRouter.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 express, { Response } from 'express';\nimport Router from 'express-promise-router';\nimport { z } from 'zod/v3';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { InputError } from '@backstage/errors';\nimport {\n AuthorizeResult,\n DefinitivePolicyDecision,\n IdentifiedPermissionMessage,\n MetadataResponse as CommonMetadataResponse,\n MetadataResponseSerializedRule as CommonMetadataResponseSerializedRule,\n Permission,\n PermissionCondition,\n PermissionCriteria,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { NoInfer, PermissionRule, PermissionRuleset } from '../types';\nimport {\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\nimport { NotImplementedError } from '@backstage/errors';\nimport { PermissionResourceRef } from './createPermissionResourceRef';\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.union([z.string(), z.array(z.string()).nonempty()]),\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 | 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 = IdentifiedPermissionMessage<\n | DefinitivePolicyDecision\n | {\n result: Array<AuthorizeResult.ALLOW | AuthorizeResult.DENY>;\n }\n>;\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 * @deprecated Please import from `@backstage/plugin-permission-common` instead.\n */\nexport type MetadataResponseSerializedRule =\n CommonMetadataResponseSerializedRule;\n\n/**\n * Response type for the .metadata endpoint.\n *\n * @public\n * @deprecated Please import from `@backstage/plugin-permission-common` instead.\n */\nexport type MetadataResponse = CommonMetadataResponse;\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\nfunction authorizeResult<TResourceType extends string, TResource>(\n criteria: PermissionCriteria<PermissionCondition<TResourceType>>,\n resource: TResource | undefined,\n getRule: (name: string) => PermissionRule<TResource, unknown, TResourceType>,\n) {\n return applyConditions(criteria, resource, getRule)\n ? AuthorizeResult.ALLOW\n : AuthorizeResult.DENY;\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 function createConditionAuthorizer<TResource>(\n permissionRuleset: PermissionRuleset<TResource>,\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean;\n/**\n * @public\n * @deprecated Use the version of `createConditionAuthorizer` that accepts a `PermissionRuleset` instead.\n */\nexport function createConditionAuthorizer<TResource, TQuery>(\n rules: PermissionRule<TResource, TQuery, string>[],\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean;\nexport function createConditionAuthorizer<TResource, TQuery>(\n rules:\n | PermissionRule<TResource, TQuery, string>[]\n | PermissionRuleset<TResource>,\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean {\n const getRule =\n 'getRuleByName' in rules\n ? (n: string) => rules.getRuleByName(n)\n : 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 * @deprecated {@link createPermissionIntegrationRouter} is deprecated\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 * Options for creating a permission integration router exposing\n * permissions and rules from multiple resource types.\n *\n * @public\n * @deprecated {@link createPermissionIntegrationRouter} is deprecated\n */\nexport type PermissionIntegrationRouterOptions<\n TResourceType1 extends string = string,\n TResource1 = any,\n TResourceType2 extends string = string,\n TResource2 = any,\n TResourceType3 extends string = string,\n TResource3 = any,\n> = {\n resources: Readonly<\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n ]\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType2,\n TResource2\n >,\n ]\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType2,\n TResource2\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType3,\n TResource3\n >,\n ]\n >;\n};\n\nclass PermissionIntegrationMetadataStore {\n readonly #rulesByTypeByName = new Map<\n string,\n Map<string, PermissionRule<unknown, unknown, string>>\n >();\n readonly #permissionsByName = new Map<string, Permission>();\n readonly #resourcesByType = new Map<\n string,\n CreatePermissionIntegrationRouterResourceOptions<string, unknown>\n >();\n readonly #serializedRules = new Array<MetadataResponseSerializedRule>();\n\n getSerializedMetadata(): MetadataResponse {\n return {\n permissions: Array.from(this.#permissionsByName.values()),\n rules: this.#serializedRules,\n };\n }\n\n hasResourceType(type: string): boolean {\n return this.#resourcesByType.has(type);\n }\n\n async getResources(\n resourceType: string,\n refs: string[],\n ): Promise<Record<string, unknown>> {\n const resource = this.#resourcesByType.get(resourceType);\n if (!resource?.getResources) {\n throw new NotImplementedError(\n `This plugin does not expose any permission rule or can't evaluate the conditions request for ${resourceType}`,\n );\n }\n\n const uniqueRefs = Array.from(new Set(refs));\n const resources = await resource.getResources(uniqueRefs);\n return Object.fromEntries(\n uniqueRefs.map((ref, index) => [ref, resources[index]]),\n );\n }\n\n getRuleMapper(resourceType: string) {\n return (name: string): PermissionRule<unknown, unknown, string> => {\n const rule = this.#rulesByTypeByName.get(resourceType)?.get(name);\n if (!rule) {\n throw new Error(\n `Permission rule '${name}' does not exist for resource type '${resourceType}'`,\n );\n }\n return rule;\n };\n }\n\n addPermissions(permissions: Permission[]) {\n for (const permission of permissions) {\n // Permission naming conflicts are silently ignored\n this.#permissionsByName.set(permission.name, permission);\n }\n }\n\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {\n for (const rule of rules) {\n const rulesByName =\n this.#rulesByTypeByName.get(rule.resourceType) ?? new Map();\n this.#rulesByTypeByName.set(rule.resourceType, rulesByName);\n\n if (rulesByName.has(rule.name)) {\n throw new Error(\n `Refused to add permission rule for type '${rule.resourceType}' with name '${rule.name}' because it already exists`,\n );\n }\n rulesByName.set(rule.name, rule);\n\n this.#serializedRules.push({\n name: rule.name,\n description: rule.description,\n resourceType: rule.resourceType,\n paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})),\n });\n }\n }\n\n addResourceType(\n resource: CreatePermissionIntegrationRouterResourceOptions<string, unknown>,\n ) {\n const { resourceType } = resource;\n\n if (this.#resourcesByType.has(resourceType)) {\n throw new Error(\n `Refused to add permission resource with type '${resourceType}' because it already exists`,\n );\n }\n this.#resourcesByType.set(resourceType, resource);\n\n if (resource.rules) {\n this.addPermissionRules(resource.rules);\n }\n\n if (resource.permissions) {\n this.addPermissions(resource.permissions);\n }\n }\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 * In case resources is provided, the routes can handle permissions\n * for multiple resource types.\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 * @deprecated use `PermissionRegistryService` instead, see {@link https://backstage.io/docs/backend-system/core-services/permissions-registry#migrating-from-createpermissionintegrationrouter | the migration section in the service docs} for more details.\n */\nexport function createPermissionIntegrationRouter<\n TResourceType1 extends string,\n TResource1,\n TResourceType2 extends string,\n TResource2,\n TResourceType3 extends string,\n TResource3,\n>(\n options?:\n | { permissions: Array<Permission> }\n | CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >\n | PermissionIntegrationRouterOptions<\n TResourceType1,\n TResource1,\n TResourceType2,\n TResource2,\n TResourceType3,\n TResource3\n >,\n): express.Router & {\n addPermissions(permissions: Permission[]): void;\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]): void;\n addResourceType<const TResourceType extends string, TResource>(\n resource: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n ): void;\n getPermissionRuleset<TResource, TQuery, TResourceType extends string>(\n resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,\n ): PermissionRuleset<TResource, TQuery, TResourceType>;\n} {\n const store = new PermissionIntegrationMetadataStore();\n\n if (options) {\n if ('resources' in options) {\n // Not technically allowed by types, but it's historically been covered by tests\n if ('permissions' in options) {\n store.addPermissions(options.permissions as Permission[]);\n }\n\n for (const resource of options.resources) {\n store.addResourceType(resource);\n }\n } else if ('resourceType' in options) {\n store.addResourceType(options);\n } else {\n store.addPermissions(options.permissions);\n }\n }\n\n const router = Router();\n\n router.use('/.well-known/backstage/permissions/', express.json());\n\n router.get('/.well-known/backstage/permissions/metadata', (_, res) => {\n res.json(store.getSerializedMetadata());\n });\n\n router.post(\n '/.well-known/backstage/permissions/apply-conditions',\n async (req, res: Response<ApplyConditionsResponse>) => {\n const parseResult = applyConditionsRequestSchema.safeParse(req.body);\n if (!parseResult.success) {\n throw new InputError(parseResult.error.toString());\n }\n\n const { items: requests } = parseResult.data;\n\n const invalidResourceTypes = requests.filter(\n i => !store.hasResourceType(i.resourceType),\n );\n if (invalidResourceTypes.length) {\n throw new InputError(\n `Unexpected resource types: ${invalidResourceTypes\n .map(i => i.resourceType)\n .join(', ')}.`,\n );\n }\n\n const resourcesByType: Record<string, Record<string, any>> = {};\n for (const requestedType of new Set(requests.map(i => i.resourceType))) {\n resourcesByType[requestedType] = await store.getResources(\n requestedType,\n requests\n .filter(r => r.resourceType === requestedType)\n .map(i => i.resourceRef)\n .flat(),\n );\n }\n\n res.json({\n items: requests.map(request => ({\n id: request.id,\n result: Array.isArray(request.resourceRef)\n ? request.resourceRef.map(resourceRef =>\n authorizeResult(\n request.conditions,\n resourcesByType[request.resourceType][resourceRef],\n store.getRuleMapper(request.resourceType),\n ),\n )\n : authorizeResult(\n request.conditions,\n resourcesByType[request.resourceType][request.resourceRef],\n store.getRuleMapper(request.resourceType),\n ),\n })),\n });\n },\n );\n\n return Object.assign(router, {\n addPermissions(permissions: Permission[]) {\n store.addPermissions(permissions);\n },\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {\n store.addPermissionRules(rules);\n },\n addResourceType<const TResourceType extends string, TResource>(\n resource: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n ) {\n store.addResourceType(resource);\n },\n getPermissionRuleset<TResource, TQuery, TResourceType extends string>(\n resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,\n ): PermissionRuleset<TResource, TQuery, TResourceType> {\n return {\n getRuleByName: store.getRuleMapper(resourceRef.resourceType),\n } as PermissionRuleset<TResource, TQuery, TResourceType>;\n },\n });\n}\n"],"names":["z","isAndCriteria","isOrCriteria","isNotCriteria","InputError","AuthorizeResult","createGetRule","NotImplementedError","zodToJsonSchema","Router","express"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createPermissionIntegrationRouter.cjs.js","sources":["../../src/integration/createPermissionIntegrationRouter.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 express, { Response } from 'express';\nimport Router from 'express-promise-router';\nimport { z } from 'zod/v3';\nimport { InputError } from '@backstage/errors';\nimport {\n AuthorizeResult,\n DefinitivePolicyDecision,\n IdentifiedPermissionMessage,\n MetadataResponse as CommonMetadataResponse,\n MetadataResponseSerializedRule as CommonMetadataResponseSerializedRule,\n Permission,\n PermissionCondition,\n PermissionCriteria,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { NoInfer, PermissionRule, PermissionRuleset } from '../types';\nimport {\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\nimport { NotImplementedError } from '@backstage/errors';\nimport { PermissionResourceRef } from './createPermissionResourceRef';\nimport {\n assertPermissionRuleParamsSchema,\n permissionRuleParamsToJsonSchema,\n validatePermissionRuleParams,\n} from './permissionRuleParams';\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.union([z.string(), z.array(z.string()).nonempty()]),\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 | 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 = IdentifiedPermissionMessage<\n | DefinitivePolicyDecision\n | {\n result: Array<AuthorizeResult.ALLOW | AuthorizeResult.DENY>;\n }\n>;\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 * @deprecated Please import from `@backstage/plugin-permission-common` instead.\n */\nexport type MetadataResponseSerializedRule =\n CommonMetadataResponseSerializedRule;\n\n/**\n * Response type for the .metadata endpoint.\n *\n * @public\n * @deprecated Please import from `@backstage/plugin-permission-common` instead.\n */\nexport type MetadataResponse = CommonMetadataResponse;\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 validatePermissionRuleParams(rule, criteria.params);\n\n return rule.apply(resource, criteria.params ?? {});\n};\n\nfunction authorizeResult<TResourceType extends string, TResource>(\n criteria: PermissionCriteria<PermissionCondition<TResourceType>>,\n resource: TResource | undefined,\n getRule: (name: string) => PermissionRule<TResource, unknown, TResourceType>,\n) {\n return applyConditions(criteria, resource, getRule)\n ? AuthorizeResult.ALLOW\n : AuthorizeResult.DENY;\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 function createConditionAuthorizer<TResource>(\n permissionRuleset: PermissionRuleset<TResource>,\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean;\n/**\n * @public\n * @deprecated Use the version of `createConditionAuthorizer` that accepts a `PermissionRuleset` instead.\n */\nexport function createConditionAuthorizer<TResource, TQuery>(\n rules: PermissionRule<TResource, TQuery, string>[],\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean;\nexport function createConditionAuthorizer<TResource, TQuery>(\n rules:\n | PermissionRule<TResource, TQuery, string>[]\n | PermissionRuleset<TResource>,\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean {\n const getRule =\n 'getRuleByName' in rules\n ? (n: string) => rules.getRuleByName(n)\n : 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 * @deprecated {@link createPermissionIntegrationRouter} is deprecated\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 * Options for creating a permission integration router exposing\n * permissions and rules from multiple resource types.\n *\n * @public\n * @deprecated {@link createPermissionIntegrationRouter} is deprecated\n */\nexport type PermissionIntegrationRouterOptions<\n TResourceType1 extends string = string,\n TResource1 = any,\n TResourceType2 extends string = string,\n TResource2 = any,\n TResourceType3 extends string = string,\n TResource3 = any,\n> = {\n resources: Readonly<\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n ]\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType2,\n TResource2\n >,\n ]\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType2,\n TResource2\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType3,\n TResource3\n >,\n ]\n >;\n};\n\nclass PermissionIntegrationMetadataStore {\n readonly #rulesByTypeByName = new Map<\n string,\n Map<string, PermissionRule<unknown, unknown, string>>\n >();\n readonly #permissionsByName = new Map<string, Permission>();\n readonly #resourcesByType = new Map<\n string,\n CreatePermissionIntegrationRouterResourceOptions<string, unknown>\n >();\n readonly #serializedRules = new Array<MetadataResponseSerializedRule>();\n\n getSerializedMetadata(): MetadataResponse {\n return {\n permissions: Array.from(this.#permissionsByName.values()),\n rules: this.#serializedRules,\n };\n }\n\n hasResourceType(type: string): boolean {\n return this.#resourcesByType.has(type);\n }\n\n async getResources(\n resourceType: string,\n refs: string[],\n ): Promise<Record<string, unknown>> {\n const resource = this.#resourcesByType.get(resourceType);\n if (!resource?.getResources) {\n throw new NotImplementedError(\n `This plugin does not expose any permission rule or can't evaluate the conditions request for ${resourceType}`,\n );\n }\n\n const uniqueRefs = Array.from(new Set(refs));\n const resources = await resource.getResources(uniqueRefs);\n return Object.fromEntries(\n uniqueRefs.map((ref, index) => [ref, resources[index]]),\n );\n }\n\n getRuleMapper(resourceType: string) {\n return (name: string): PermissionRule<unknown, unknown, string> => {\n const rule = this.#rulesByTypeByName.get(resourceType)?.get(name);\n if (!rule) {\n throw new Error(\n `Permission rule '${name}' does not exist for resource type '${resourceType}'`,\n );\n }\n return rule;\n };\n }\n\n addPermissions(permissions: Permission[]) {\n for (const permission of permissions) {\n // Permission naming conflicts are silently ignored\n this.#permissionsByName.set(permission.name, permission);\n }\n }\n\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {\n for (const rule of rules) {\n assertPermissionRuleParamsSchema(rule);\n const rulesByName =\n this.#rulesByTypeByName.get(rule.resourceType) ?? new Map();\n this.#rulesByTypeByName.set(rule.resourceType, rulesByName);\n\n if (rulesByName.has(rule.name)) {\n throw new Error(\n `Refused to add permission rule for type '${rule.resourceType}' with name '${rule.name}' because it already exists`,\n );\n }\n rulesByName.set(rule.name, rule);\n\n this.#serializedRules.push({\n name: rule.name,\n description: rule.description,\n resourceType: rule.resourceType,\n paramsSchema: permissionRuleParamsToJsonSchema(rule),\n });\n }\n }\n\n addResourceType(\n resource: CreatePermissionIntegrationRouterResourceOptions<string, unknown>,\n ) {\n const { resourceType } = resource;\n\n if (this.#resourcesByType.has(resourceType)) {\n throw new Error(\n `Refused to add permission resource with type '${resourceType}' because it already exists`,\n );\n }\n this.#resourcesByType.set(resourceType, resource);\n\n if (resource.rules) {\n this.addPermissionRules(resource.rules);\n }\n\n if (resource.permissions) {\n this.addPermissions(resource.permissions);\n }\n }\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 * In case resources is provided, the routes can handle permissions\n * for multiple resource types.\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 * @deprecated use `PermissionRegistryService` instead, see {@link https://backstage.io/docs/backend-system/core-services/permissions-registry#migrating-from-createpermissionintegrationrouter | the migration section in the service docs} for more details.\n */\nexport function createPermissionIntegrationRouter<\n TResourceType1 extends string,\n TResource1,\n TResourceType2 extends string,\n TResource2,\n TResourceType3 extends string,\n TResource3,\n>(\n options?:\n | { permissions: Array<Permission> }\n | CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >\n | PermissionIntegrationRouterOptions<\n TResourceType1,\n TResource1,\n TResourceType2,\n TResource2,\n TResourceType3,\n TResource3\n >,\n): express.Router & {\n addPermissions(permissions: Permission[]): void;\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]): void;\n addResourceType<const TResourceType extends string, TResource>(\n resource: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n ): void;\n getPermissionRuleset<TResource, TQuery, TResourceType extends string>(\n resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,\n ): PermissionRuleset<TResource, TQuery, TResourceType>;\n} {\n const store = new PermissionIntegrationMetadataStore();\n\n if (options) {\n if ('resources' in options) {\n // Not technically allowed by types, but it's historically been covered by tests\n if ('permissions' in options) {\n store.addPermissions(options.permissions as Permission[]);\n }\n\n for (const resource of options.resources) {\n store.addResourceType(resource);\n }\n } else if ('resourceType' in options) {\n store.addResourceType(options);\n } else {\n store.addPermissions(options.permissions);\n }\n }\n\n const router = Router();\n\n router.use('/.well-known/backstage/permissions/', express.json());\n\n router.get('/.well-known/backstage/permissions/metadata', (_, res) => {\n res.json(store.getSerializedMetadata());\n });\n\n router.post(\n '/.well-known/backstage/permissions/apply-conditions',\n async (req, res: Response<ApplyConditionsResponse>) => {\n const parseResult = applyConditionsRequestSchema.safeParse(req.body);\n if (!parseResult.success) {\n throw new InputError(parseResult.error.toString());\n }\n\n const { items: requests } = parseResult.data;\n\n const invalidResourceTypes = requests.filter(\n i => !store.hasResourceType(i.resourceType),\n );\n if (invalidResourceTypes.length) {\n throw new InputError(\n `Unexpected resource types: ${invalidResourceTypes\n .map(i => i.resourceType)\n .join(', ')}.`,\n );\n }\n\n const resourcesByType: Record<string, Record<string, any>> = {};\n for (const requestedType of new Set(requests.map(i => i.resourceType))) {\n resourcesByType[requestedType] = await store.getResources(\n requestedType,\n requests\n .filter(r => r.resourceType === requestedType)\n .map(i => i.resourceRef)\n .flat(),\n );\n }\n\n res.json({\n items: requests.map(request => ({\n id: request.id,\n result: Array.isArray(request.resourceRef)\n ? request.resourceRef.map(resourceRef =>\n authorizeResult(\n request.conditions,\n resourcesByType[request.resourceType][resourceRef],\n store.getRuleMapper(request.resourceType),\n ),\n )\n : authorizeResult(\n request.conditions,\n resourcesByType[request.resourceType][request.resourceRef],\n store.getRuleMapper(request.resourceType),\n ),\n })),\n });\n },\n );\n\n return Object.assign(router, {\n addPermissions(permissions: Permission[]) {\n store.addPermissions(permissions);\n },\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {\n store.addPermissionRules(rules);\n },\n addResourceType<const TResourceType extends string, TResource>(\n resource: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n ) {\n store.addResourceType(resource);\n },\n getPermissionRuleset<TResource, TQuery, TResourceType extends string>(\n resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,\n ): PermissionRuleset<TResource, TQuery, TResourceType> {\n return {\n getRuleByName: store.getRuleMapper(resourceRef.resourceType),\n } as PermissionRuleset<TResource, TQuery, TResourceType>;\n },\n });\n}\n"],"names":["z","isAndCriteria","isOrCriteria","isNotCriteria","validatePermissionRuleParams","AuthorizeResult","createGetRule","NotImplementedError","assertPermissionRuleParamsSchema","permissionRuleParamsToJsonSchema","Router","express","InputError"],"mappings":";;;;;;;;;;;;;;;AA8CA,MAAM,2BAEFA,IAAA,CAAE,IAAA;AAAA,EAAK,MACTA,KAAE,KAAA,CAAM;AAAA,IACNA,IAAA,CAAE,MAAA,CAAO,EAAE,KAAA,EAAOA,IAAA,CAAE,MAAM,wBAAwB,CAAA,CAAE,QAAA,EAAS,EAAG,CAAA;AAAA,IAChEA,IAAA,CAAE,MAAA,CAAO,EAAE,KAAA,EAAOA,IAAA,CAAE,MAAM,wBAAwB,CAAA,CAAE,QAAA,EAAS,EAAG,CAAA;AAAA,IAChEA,IAAA,CAAE,MAAA,CAAO,EAAE,GAAA,EAAK,0BAA0B,CAAA;AAAA,IAC1CA,KAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAE,MAAA,EAAO;AAAA,MACf,YAAA,EAAcA,KAAE,MAAA,EAAO;AAAA,MACvB,QAAQA,IAAA,CAAE,MAAA,CAAOA,KAAE,GAAA,EAAK,EAAE,QAAA;AAAS,KACpC;AAAA,GACF;AACH,CAAA;AAEA,MAAM,4BAAA,GAA+BA,KAAE,MAAA,CAAO;AAAA,EAC5C,OAAOA,IAAA,CAAE,KAAA;AAAA,IACPA,KAAE,MAAA,CAAO;AAAA,MACP,EAAA,EAAIA,KAAE,MAAA,EAAO;AAAA,MACb,WAAA,EAAaA,IAAA,CAAE,KAAA,CAAM,CAACA,KAAE,MAAA,EAAO,EAAGA,IAAA,CAAE,KAAA,CAAMA,KAAE,MAAA,EAAQ,CAAA,CAAE,QAAA,EAAU,CAAC,CAAA;AAAA,MACjE,YAAA,EAAcA,KAAE,MAAA,EAAO;AAAA,MACvB,UAAA,EAAY;AAAA,KACb;AAAA;AAEL,CAAC,CAAA;AA+DD,MAAM,eAAA,GAAkB,CACtB,QAAA,EACA,QAAA,EACA,OAAA,KACY;AAIZ,EAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAIC,kBAAA,CAAc,QAAQ,CAAA,EAAG;AAC3B,IAAA,OAAO,SAAS,KAAA,CAAM,KAAA;AAAA,MAAM,CAAA,KAAA,KAC1B,eAAA,CAAgB,KAAA,EAAO,QAAA,EAAU,OAAO;AAAA,KAC1C;AAAA,EACF,CAAA,MAAA,IAAWC,iBAAA,CAAa,QAAQ,CAAA,EAAG;AACjC,IAAA,OAAO,SAAS,KAAA,CAAM,IAAA;AAAA,MAAK,CAAA,KAAA,KACzB,eAAA,CAAgB,KAAA,EAAO,QAAA,EAAU,OAAO;AAAA,KAC1C;AAAA,EACF,CAAA,MAAA,IAAWC,kBAAA,CAAc,QAAQ,CAAA,EAAG;AAClC,IAAA,OAAO,CAAC,eAAA,CAAgB,QAAA,CAAS,GAAA,EAAK,UAAU,OAAO,CAAA;AAAA,EACzD;AAEA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA;AAClC,EAAAC,iDAAA,CAA6B,IAAA,EAAM,SAAS,MAAM,CAAA;AAElD,EAAA,OAAO,KAAK,KAAA,CAAM,QAAA,EAAU,QAAA,CAAS,MAAA,IAAU,EAAE,CAAA;AACnD,CAAA;AAEA,SAAS,eAAA,CACP,QAAA,EACA,QAAA,EACA,OAAA,EACA;AACA,EAAA,OAAO,gBAAgB,QAAA,EAAU,QAAA,EAAU,OAAO,CAAA,GAC9CC,sCAAA,CAAgB,QAChBA,sCAAA,CAAgB,IAAA;AACtB;AAkBO,SAAS,0BACd,KAAA,EAGwE;AACxE,EAAA,MAAM,OAAA,GACJ,eAAA,IAAmB,KAAA,GACf,CAAC,CAAA,KAAc,MAAM,aAAA,CAAc,CAAC,CAAA,GACpCC,kBAAA,CAAc,KAAK,CAAA;AAEzB,EAAA,OAAO,CACL,UACA,QAAA,KACY;AACZ,IAAA,IAAI,QAAA,CAAS,MAAA,KAAWD,sCAAA,CAAgB,WAAA,EAAa;AACnD,MAAA,OAAO,eAAA,CAAgB,QAAA,CAAS,UAAA,EAAY,QAAA,EAAU,OAAO,CAAA;AAAA,IAC/D;AAEA,IAAA,OAAO,QAAA,CAAS,WAAWA,sCAAA,CAAgB,KAAA;AAAA,EAC7C,CAAA;AACF;AA0EA,MAAM,kCAAA,CAAmC;AAAA,EAC9B,kBAAA,uBAAyB,GAAA,EAGhC;AAAA,EACO,kBAAA,uBAAyB,GAAA,EAAwB;AAAA,EACjD,gBAAA,uBAAuB,GAAA,EAG9B;AAAA,EACO,gBAAA,GAAmB,IAAI,KAAA,EAAsC;AAAA,EAEtE,qBAAA,GAA0C;AACxC,IAAA,OAAO;AAAA,MACL,aAAa,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,kBAAA,CAAmB,QAAQ,CAAA;AAAA,MACxD,OAAO,IAAA,CAAK;AAAA,KACd;AAAA,EACF;AAAA,EAEA,gBAAgB,IAAA,EAAuB;AACrC,IAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,IAAI,CAAA;AAAA,EACvC;AAAA,EAEA,MAAM,YAAA,CACJ,YAAA,EACA,IAAA,EACkC;AAClC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,YAAY,CAAA;AACvD,IAAA,IAAI,CAAC,UAAU,YAAA,EAAc;AAC3B,MAAA,MAAM,IAAIE,0BAAA;AAAA,QACR,gGAAgG,YAAY,CAAA;AAAA,OAC9G;AAAA,IACF;AAEA,IAAA,MAAM,aAAa,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,IAAI,CAAC,CAAA;AAC3C,IAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,YAAA,CAAa,UAAU,CAAA;AACxD,IAAA,OAAO,MAAA,CAAO,WAAA;AAAA,MACZ,UAAA,CAAW,GAAA,CAAI,CAAC,GAAA,EAAK,KAAA,KAAU,CAAC,GAAA,EAAK,SAAA,CAAU,KAAK,CAAC,CAAC;AAAA,KACxD;AAAA,EACF;AAAA,EAEA,cAAc,YAAA,EAAsB;AAClC,IAAA,OAAO,CAAC,IAAA,KAA2D;AACjE,MAAA,MAAM,OAAO,IAAA,CAAK,kBAAA,CAAmB,IAAI,YAAY,CAAA,EAAG,IAAI,IAAI,CAAA;AAChE,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,iBAAA,EAAoB,IAAI,CAAA,oCAAA,EAAuC,YAAY,CAAA,CAAA;AAAA,SAC7E;AAAA,MACF;AACA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,EACF;AAAA,EAEA,eAAe,WAAA,EAA2B;AACxC,IAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AAEpC,MAAA,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,UAAA,CAAW,IAAA,EAAM,UAAU,CAAA;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,mBAAmB,KAAA,EAAmD;AACpE,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAAC,qDAAA,CAAiC,IAAI,CAAA;AACrC,MAAA,MAAM,WAAA,GACJ,KAAK,kBAAA,CAAmB,GAAA,CAAI,KAAK,YAAY,CAAA,wBAAS,GAAA,EAAI;AAC5D,MAAA,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,IAAA,CAAK,YAAA,EAAc,WAAW,CAAA;AAE1D,MAAA,IAAI,WAAA,CAAY,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AAC9B,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,yCAAA,EAA4C,IAAA,CAAK,YAAY,CAAA,aAAA,EAAgB,KAAK,IAAI,CAAA,2BAAA;AAAA,SACxF;AAAA,MACF;AACA,MAAA,WAAA,CAAY,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAE/B,MAAA,IAAA,CAAK,iBAAiB,IAAA,CAAK;AAAA,QACzB,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,aAAa,IAAA,CAAK,WAAA;AAAA,QAClB,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB,YAAA,EAAcC,sDAAiC,IAAI;AAAA,OACpD,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEA,gBACE,QAAA,EACA;AACA,IAAA,MAAM,EAAE,cAAa,GAAI,QAAA;AAEzB,IAAA,IAAI,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,YAAY,CAAA,EAAG;AAC3C,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,iDAAiD,YAAY,CAAA,2BAAA;AAAA,OAC/D;AAAA,IACF;AACA,IAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,YAAA,EAAc,QAAQ,CAAA;AAEhD,IAAA,IAAI,SAAS,KAAA,EAAO;AAClB,MAAA,IAAA,CAAK,kBAAA,CAAmB,SAAS,KAAK,CAAA;AAAA,IACxC;AAEA,IAAA,IAAI,SAAS,WAAA,EAAa;AACxB,MAAA,IAAA,CAAK,cAAA,CAAe,SAAS,WAAW,CAAA;AAAA,IAC1C;AAAA,EACF;AACF;AA4CO,SAAS,kCAQd,OAAA,EA0BA;AACA,EAAA,MAAM,KAAA,GAAQ,IAAI,kCAAA,EAAmC;AAErD,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,IAAI,eAAe,OAAA,EAAS;AAE1B,MAAA,IAAI,iBAAiB,OAAA,EAAS;AAC5B,QAAA,KAAA,CAAM,cAAA,CAAe,QAAQ,WAA2B,CAAA;AAAA,MAC1D;AAEA,MAAA,KAAA,MAAW,QAAA,IAAY,QAAQ,SAAA,EAAW;AACxC,QAAA,KAAA,CAAM,gBAAgB,QAAQ,CAAA;AAAA,MAChC;AAAA,IACF,CAAA,MAAA,IAAW,kBAAkB,OAAA,EAAS;AACpC,MAAA,KAAA,CAAM,gBAAgB,OAAO,CAAA;AAAA,IAC/B,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,cAAA,CAAe,QAAQ,WAAW,CAAA;AAAA,IAC1C;AAAA,EACF;AAEA,EAAA,MAAM,SAASC,uBAAA,EAAO;AAEtB,EAAA,MAAA,CAAO,GAAA,CAAI,qCAAA,EAAuCC,wBAAA,CAAQ,IAAA,EAAM,CAAA;AAEhE,EAAA,MAAA,CAAO,GAAA,CAAI,6CAAA,EAA+C,CAAC,CAAA,EAAG,GAAA,KAAQ;AACpE,IAAA,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,qBAAA,EAAuB,CAAA;AAAA,EACxC,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,qDAAA;AAAA,IACA,OAAO,KAAK,GAAA,KAA2C;AACrD,MAAA,MAAM,WAAA,GAAc,4BAAA,CAA6B,SAAA,CAAU,GAAA,CAAI,IAAI,CAAA;AACnE,MAAA,IAAI,CAAC,YAAY,OAAA,EAAS;AACxB,QAAA,MAAM,IAAIC,iBAAA,CAAW,WAAA,CAAY,KAAA,CAAM,UAAU,CAAA;AAAA,MACnD;AAEA,MAAA,MAAM,EAAE,KAAA,EAAO,QAAA,EAAS,GAAI,WAAA,CAAY,IAAA;AAExC,MAAA,MAAM,uBAAuB,QAAA,CAAS,MAAA;AAAA,QACpC,CAAA,CAAA,KAAK,CAAC,KAAA,CAAM,eAAA,CAAgB,EAAE,YAAY;AAAA,OAC5C;AACA,MAAA,IAAI,qBAAqB,MAAA,EAAQ;AAC/B,QAAA,MAAM,IAAIA,iBAAA;AAAA,UACR,CAAA,2BAAA,EAA8B,qBAC3B,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,YAAY,CAAA,CACvB,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,SACf;AAAA,MACF;AAEA,MAAA,MAAM,kBAAuD,EAAC;AAC9D,MAAA,KAAA,MAAW,aAAA,IAAiB,IAAI,GAAA,CAAI,QAAA,CAAS,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,YAAY,CAAC,CAAA,EAAG;AACtE,QAAA,eAAA,CAAgB,aAAa,CAAA,GAAI,MAAM,KAAA,CAAM,YAAA;AAAA,UAC3C,aAAA;AAAA,UACA,QAAA,CACG,MAAA,CAAO,CAAA,CAAA,KAAK,CAAA,CAAE,YAAA,KAAiB,aAAa,CAAA,CAC5C,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,WAAW,CAAA,CACtB,IAAA;AAAK,SACV;AAAA,MACF;AAEA,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,KAAA,EAAO,QAAA,CAAS,GAAA,CAAI,CAAA,OAAA,MAAY;AAAA,UAC9B,IAAI,OAAA,CAAQ,EAAA;AAAA,UACZ,QAAQ,KAAA,CAAM,OAAA,CAAQ,QAAQ,WAAW,CAAA,GACrC,QAAQ,WAAA,CAAY,GAAA;AAAA,YAAI,CAAA,WAAA,KACtB,eAAA;AAAA,cACE,OAAA,CAAQ,UAAA;AAAA,cACR,eAAA,CAAgB,OAAA,CAAQ,YAAY,CAAA,CAAE,WAAW,CAAA;AAAA,cACjD,KAAA,CAAM,aAAA,CAAc,OAAA,CAAQ,YAAY;AAAA;AAC1C,WACF,GACA,eAAA;AAAA,YACE,OAAA,CAAQ,UAAA;AAAA,YACR,eAAA,CAAgB,OAAA,CAAQ,YAAY,CAAA,CAAE,QAAQ,WAAW,CAAA;AAAA,YACzD,KAAA,CAAM,aAAA,CAAc,OAAA,CAAQ,YAAY;AAAA;AAC1C,SACN,CAAE;AAAA,OACH,CAAA;AAAA,IACH;AAAA,GACF;AAEA,EAAA,OAAO,MAAA,CAAO,OAAO,MAAA,EAAQ;AAAA,IAC3B,eAAe,WAAA,EAA2B;AACxC,MAAA,KAAA,CAAM,eAAe,WAAW,CAAA;AAAA,IAClC,CAAA;AAAA,IACA,mBAAmB,KAAA,EAAmD;AACpE,MAAA,KAAA,CAAM,mBAAmB,KAAK,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,gBACE,QAAA,EAIA;AACA,MAAA,KAAA,CAAM,gBAAgB,QAAQ,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,qBACE,WAAA,EACqD;AACrD,MAAA,OAAO;AAAA,QACL,aAAA,EAAe,KAAA,CAAM,aAAA,CAAc,WAAA,CAAY,YAAY;AAAA,OAC7D;AAAA,IACF;AAAA,GACD,CAAA;AACH;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPermissionRule.cjs.js","sources":["../../src/integration/createPermissionRule.ts"],"sourcesContent":["/*\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 {\n PermissionCriteria,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport { NoInfer, PermissionRule } from '../types';\nimport { z } from 'zod/v3';\nimport { PermissionResourceRef } from './createPermissionResourceRef';\n\n/**\n * @public\n */\nexport type CreatePermissionRuleOptions<\n TRef extends PermissionResourceRef,\n TParams extends PermissionRuleParams,\n> = TRef extends PermissionResourceRef<infer IResource, infer IQuery, any>\n ? {\n name: string;\n description: string;\n\n resourceRef: TRef;\n\n /**\n * A
|
|
1
|
+
{"version":3,"file":"createPermissionRule.cjs.js","sources":["../../src/integration/createPermissionRule.ts"],"sourcesContent":["/*\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 {\n PermissionCriteria,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n} from '@standard-schema/spec';\nimport { NoInfer, PermissionRule } from '../types';\nimport { z } from 'zod/v3';\nimport { PermissionResourceRef } from './createPermissionResourceRef';\nimport { assertPermissionRuleParamsSchema } from './permissionRuleParams';\n\n/**\n * @public\n */\nexport type CreatePermissionRuleOptions<\n TRef extends PermissionResourceRef,\n TParams extends PermissionRuleParams,\n> = TRef extends PermissionResourceRef<infer IResource, infer IQuery, any>\n ? {\n name: string;\n description: string;\n\n resourceRef: TRef;\n\n /**\n * A Standard Schema that reflects the structure of the parameters that are passed to the rule.\n * The schema must validate synchronously and support JSON Schema conversion.\n */\n paramsSchema?: StandardSchemaV1<TParams> & StandardJSONSchemaV1<TParams>;\n\n /**\n * Apply this rule to a resource already loaded from a backing data source. The params are\n * arguments supplied for the rule; for example, a rule could be `isOwner` with entityRefs as the\n * params.\n */\n apply(resource: IResource, params: NoInfer<TParams>): boolean;\n\n /**\n * Translate this rule to criteria suitable for use in querying a backing data store. The criteria\n * can be used for loading a collection of resources efficiently with conditional criteria already\n * applied.\n */\n toQuery(params: NoInfer<TParams>): PermissionCriteria<IQuery>;\n }\n : never;\n\n/**\n * Helper function to create a {@link PermissionRule} for a specific resource type using a {@link PermissionResourceRef}.\n *\n * @public\n */\nexport function createPermissionRule<\n TRef extends PermissionResourceRef,\n TParams extends PermissionRuleParams = undefined,\n>(\n rule: CreatePermissionRuleOptions<TRef, TParams>,\n): PermissionRule<\n TRef['TResource'],\n TRef['TQuery'],\n TRef['resourceType'],\n TParams\n>;\n/**\n * @public\n * @deprecated Zod v3 parameter schemas are deprecated, switch to a JSON Schema-compatible Standard Schema instead, such as Zod v4.\n */\nexport function createPermissionRule<\n TRef extends PermissionResourceRef,\n TParams extends PermissionRuleParams = undefined,\n>(rule: {\n name: string;\n description: string;\n resourceRef: TRef;\n paramsSchema: z.ZodSchema<TParams>;\n apply(resource: TRef['TResource'], params: NoInfer<TParams>): boolean;\n toQuery(params: NoInfer<TParams>): PermissionCriteria<TRef['TQuery']>;\n}): PermissionRule<\n TRef['TResource'],\n TRef['TQuery'],\n TRef['resourceType'],\n TParams\n>;\n/**\n * Helper function to ensure that {@link PermissionRule} definitions are typed correctly.\n *\n * @deprecated Use the version of `createPermissionRule` that accepts a `resourceRef` option instead.\n * @public\n */\nexport function createPermissionRule<\n TResource,\n TQuery,\n TResourceType extends string,\n TParams extends PermissionRuleParams = undefined,\n>(\n rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,\n): PermissionRule<TResource, TQuery, TResourceType, TParams>;\nexport function createPermissionRule<\n TResource,\n TQuery,\n TResourceType extends string,\n TRef extends PermissionResourceRef,\n TParams extends PermissionRuleParams = undefined,\n>(\n rule:\n | PermissionRule<TResource, TQuery, TResourceType, TParams>\n | CreatePermissionRuleOptions<TRef, TParams>\n | {\n name: string;\n description: string;\n resourceRef: TRef;\n paramsSchema: z.ZodSchema<TParams>;\n apply(resource: TRef['TResource'], params: NoInfer<TParams>): boolean;\n toQuery(params: NoInfer<TParams>): PermissionCriteria<TRef['TQuery']>;\n },\n): PermissionRule<TResource, TQuery, TResourceType, TParams> {\n assertPermissionRuleParamsSchema(rule);\n if ('resourceRef' in rule) {\n return {\n ...rule,\n resourceType: rule.resourceRef.resourceType as TResourceType,\n } as PermissionRule<TResource, TQuery, TResourceType, TParams>;\n }\n return rule;\n}\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 * @deprecated Use {@link (createPermissionRule:1)} directly instead with the resourceRef option.\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"],"names":["assertPermissionRuleParamsSchema"],"mappings":";;;;AAkHO,SAAS,qBAOd,IAAA,EAW2D;AAC3D,EAAAA,qDAAA,CAAiC,IAAI,CAAA;AACrC,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,IAAA,OAAO;AAAA,MACL,GAAG,IAAA;AAAA,MACH,YAAA,EAAc,KAAK,WAAA,CAAY;AAAA,KACjC;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAWO,MAAM,wBAAA,GACX,MACA,CACE,IAAA,KAEA,qBAAqB,IAAI;;;;;"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
var v3 = require('zod/v3');
|
|
5
|
+
var zodToJsonSchema = require('zod-to-json-schema');
|
|
6
|
+
var helpers = require('../packages/backend-internal/src/wiring/helpers.cjs.js');
|
|
7
|
+
require('../packages/backend-internal/src/wiring/OpaqueExtensionPointFactoryMiddleware.cjs.js');
|
|
8
|
+
|
|
9
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var zodToJsonSchema__default = /*#__PURE__*/_interopDefaultCompat(zodToJsonSchema);
|
|
12
|
+
|
|
13
|
+
function supportsJsonSchema(schema) {
|
|
14
|
+
const standard = schema?.["~standard"];
|
|
15
|
+
return typeof standard?.validate === "function" && typeof standard.jsonSchema?.input === "function";
|
|
16
|
+
}
|
|
17
|
+
function isZodSchema(schema) {
|
|
18
|
+
return typeof schema === "object" && schema !== null && "_def" in schema && typeof schema._parse === "function" && typeof schema.safeParse === "function";
|
|
19
|
+
}
|
|
20
|
+
function assertPermissionRuleParamsSchema(rule) {
|
|
21
|
+
if (rule.paramsSchema && !supportsJsonSchema(rule.paramsSchema) && !isZodSchema(rule.paramsSchema)) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Permission rule '${rule.name}' parameter schema does not support JSON Schema conversion`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function validatePermissionRuleParams(rule, params) {
|
|
28
|
+
if (supportsJsonSchema(rule.paramsSchema)) {
|
|
29
|
+
const result = rule.paramsSchema["~standard"].validate(params);
|
|
30
|
+
if (helpers.isPromise(result)) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Permission rule '${rule.name}' parameter schema returned a Promise; async schemas are not supported`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
if (result.issues) {
|
|
36
|
+
throw new errors.InputError(
|
|
37
|
+
"Parameters to rule are invalid",
|
|
38
|
+
new Error(result.issues.map((issue) => issue.message).join("; "))
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (isZodSchema(rule.paramsSchema)) {
|
|
44
|
+
const result = rule.paramsSchema.safeParse(params);
|
|
45
|
+
if (!result.success) {
|
|
46
|
+
throw new errors.InputError("Parameters to rule are invalid", result.error);
|
|
47
|
+
}
|
|
48
|
+
} else if (rule.paramsSchema) {
|
|
49
|
+
assertPermissionRuleParamsSchema(rule);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function permissionRuleParamsToJsonSchema(rule) {
|
|
53
|
+
if (supportsJsonSchema(rule.paramsSchema)) {
|
|
54
|
+
return rule.paramsSchema["~standard"].jsonSchema.input({
|
|
55
|
+
target: "draft-07"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (isZodSchema(rule.paramsSchema)) {
|
|
59
|
+
return zodToJsonSchema__default.default(rule.paramsSchema);
|
|
60
|
+
}
|
|
61
|
+
assertPermissionRuleParamsSchema(rule);
|
|
62
|
+
return zodToJsonSchema__default.default(v3.z.object({}));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
exports.assertPermissionRuleParamsSchema = assertPermissionRuleParamsSchema;
|
|
66
|
+
exports.permissionRuleParamsToJsonSchema = permissionRuleParamsToJsonSchema;
|
|
67
|
+
exports.validatePermissionRuleParams = validatePermissionRuleParams;
|
|
68
|
+
//# sourceMappingURL=permissionRuleParams.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionRuleParams.cjs.js","sources":["../../src/integration/permissionRuleParams.ts"],"sourcesContent":["/*\n * Copyright 2026 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 { InputError } from '@backstage/errors';\nimport { isPromise } from '@internal/backend';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { z } from 'zod/v3';\nimport zodToJsonSchema from 'zod-to-json-schema';\n\ntype RuleWithParamsSchema = {\n name: string;\n paramsSchema?: unknown;\n};\n\ntype StandardSchemaWithJsonSchemaInput = StandardSchemaV1 & {\n '~standard': {\n jsonSchema: {\n input(options: { target: 'draft-07' }): Record<string, unknown>;\n };\n };\n};\n\nfunction supportsJsonSchema(\n schema: unknown,\n): schema is StandardSchemaWithJsonSchemaInput {\n const standard = (schema as StandardSchemaV1 | undefined)?.[\n '~standard'\n ] as unknown as\n | {\n validate?: unknown;\n jsonSchema?: { input?: unknown };\n }\n | undefined;\n return (\n typeof standard?.validate === 'function' &&\n typeof standard.jsonSchema?.input === 'function'\n );\n}\n\nfunction isZodSchema(schema: unknown): schema is z.ZodSchema<any> {\n return (\n typeof schema === 'object' &&\n schema !== null &&\n '_def' in schema &&\n typeof (schema as { _parse?: unknown })._parse === 'function' &&\n typeof (schema as { safeParse?: unknown }).safeParse === 'function'\n );\n}\n\n/** Ensures that a rule parameter schema can be serialized as permission metadata. */\nexport function assertPermissionRuleParamsSchema(\n rule: RuleWithParamsSchema,\n): void {\n if (\n rule.paramsSchema &&\n !supportsJsonSchema(rule.paramsSchema) &&\n !isZodSchema(rule.paramsSchema)\n ) {\n throw new Error(\n `Permission rule '${rule.name}' parameter schema does not support JSON Schema conversion`,\n );\n }\n}\n\n/**\n * Validates rule parameters using either the Standard Schema or legacy Zod schema.\n * Standard Schema validation must be synchronous because rule evaluation is synchronous.\n */\nexport function validatePermissionRuleParams(\n rule: RuleWithParamsSchema,\n params: unknown,\n): void {\n if (supportsJsonSchema(rule.paramsSchema)) {\n const result = rule.paramsSchema['~standard'].validate(params);\n if (isPromise(result)) {\n throw new Error(\n `Permission rule '${rule.name}' parameter schema returned a Promise; async schemas are not supported`,\n );\n }\n if (result.issues) {\n throw new InputError(\n 'Parameters to rule are invalid',\n new Error(result.issues.map(issue => issue.message).join('; ')),\n );\n }\n return;\n }\n\n if (isZodSchema(rule.paramsSchema)) {\n const result = rule.paramsSchema.safeParse(params);\n if (!result.success) {\n throw new InputError('Parameters to rule are invalid', result.error);\n }\n } else if (rule.paramsSchema) {\n assertPermissionRuleParamsSchema(rule);\n }\n}\n\n/** Converts a rule parameter schema to JSON Schema for permission metadata. */\nexport function permissionRuleParamsToJsonSchema(\n rule: RuleWithParamsSchema,\n): ReturnType<typeof zodToJsonSchema> {\n if (supportsJsonSchema(rule.paramsSchema)) {\n return rule.paramsSchema['~standard'].jsonSchema.input({\n target: 'draft-07',\n }) as ReturnType<typeof zodToJsonSchema>;\n }\n\n if (isZodSchema(rule.paramsSchema)) {\n return zodToJsonSchema(rule.paramsSchema);\n }\n\n assertPermissionRuleParamsSchema(rule);\n return zodToJsonSchema(z.object({}));\n}\n"],"names":["isPromise","InputError","zodToJsonSchema","z"],"mappings":";;;;;;;;;;;;AAmCA,SAAS,mBACP,MAAA,EAC6C;AAC7C,EAAA,MAAM,QAAA,GAAY,SAChB,WACF,CAAA;AAMA,EAAA,OACE,OAAO,QAAA,EAAU,QAAA,KAAa,cAC9B,OAAO,QAAA,CAAS,YAAY,KAAA,KAAU,UAAA;AAE1C;AAEA,SAAS,YAAY,MAAA,EAA6C;AAChE,EAAA,OACE,OAAO,MAAA,KAAW,QAAA,IAClB,MAAA,KAAW,IAAA,IACX,MAAA,IAAU,MAAA,IACV,OAAQ,MAAA,CAAgC,MAAA,KAAW,UAAA,IACnD,OAAQ,OAAmC,SAAA,KAAc,UAAA;AAE7D;AAGO,SAAS,iCACd,IAAA,EACM;AACN,EAAA,IACE,IAAA,CAAK,YAAA,IACL,CAAC,kBAAA,CAAmB,IAAA,CAAK,YAAY,CAAA,IACrC,CAAC,WAAA,CAAY,IAAA,CAAK,YAAY,CAAA,EAC9B;AACA,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,iBAAA,EAAoB,KAAK,IAAI,CAAA,0DAAA;AAAA,KAC/B;AAAA,EACF;AACF;AAMO,SAAS,4BAAA,CACd,MACA,MAAA,EACM;AACN,EAAA,IAAI,kBAAA,CAAmB,IAAA,CAAK,YAAY,CAAA,EAAG;AACzC,IAAA,MAAM,SAAS,IAAA,CAAK,YAAA,CAAa,WAAW,CAAA,CAAE,SAAS,MAAM,CAAA;AAC7D,IAAA,IAAIA,iBAAA,CAAU,MAAM,CAAA,EAAG;AACrB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,iBAAA,EAAoB,KAAK,IAAI,CAAA,sEAAA;AAAA,OAC/B;AAAA,IACF;AACA,IAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,MAAA,MAAM,IAAIC,iBAAA;AAAA,QACR,gCAAA;AAAA,QACA,IAAI,KAAA,CAAM,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,CAAA,KAAA,KAAS,KAAA,CAAM,OAAO,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC;AAAA,OAChE;AAAA,IACF;AACA,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,WAAA,CAAY,IAAA,CAAK,YAAY,CAAA,EAAG;AAClC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,YAAA,CAAa,SAAA,CAAU,MAAM,CAAA;AACjD,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,MAAA,MAAM,IAAIA,iBAAA,CAAW,gCAAA,EAAkC,MAAA,CAAO,KAAK,CAAA;AAAA,IACrE;AAAA,EACF,CAAA,MAAA,IAAW,KAAK,YAAA,EAAc;AAC5B,IAAA,gCAAA,CAAiC,IAAI,CAAA;AAAA,EACvC;AACF;AAGO,SAAS,iCACd,IAAA,EACoC;AACpC,EAAA,IAAI,kBAAA,CAAmB,IAAA,CAAK,YAAY,CAAA,EAAG;AACzC,IAAA,OAAO,IAAA,CAAK,YAAA,CAAa,WAAW,CAAA,CAAE,WAAW,KAAA,CAAM;AAAA,MACrD,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,WAAA,CAAY,IAAA,CAAK,YAAY,CAAA,EAAG;AAClC,IAAA,OAAOC,gCAAA,CAAgB,KAAK,YAAY,CAAA;AAAA,EAC1C;AAEA,EAAA,gCAAA,CAAiC,IAAI,CAAA;AACrC,EAAA,OAAOA,gCAAA,CAAgBC,IAAA,CAAE,MAAA,CAAO,EAAE,CAAC,CAAA;AACrC;;;;;;"}
|
package/dist/packages/backend-internal/src/wiring/OpaqueExtensionPointFactoryMiddleware.cjs.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var OpaqueType = require('../../../opaque-internal/src/OpaqueType.cjs.js');
|
|
4
|
+
|
|
5
|
+
OpaqueType.OpaqueType.create({
|
|
6
|
+
type: "@backstage/ExtensionPointFactoryMiddleware",
|
|
7
|
+
versions: ["v1"]
|
|
8
|
+
});
|
|
9
|
+
//# sourceMappingURL=OpaqueExtensionPointFactoryMiddleware.cjs.js.map
|
package/dist/packages/backend-internal/src/wiring/OpaqueExtensionPointFactoryMiddleware.cjs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpaqueExtensionPointFactoryMiddleware.cjs.js","sources":["../../../../../../../packages/backend-internal/src/wiring/OpaqueExtensionPointFactoryMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2026 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 { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExtensionPointFactoryMiddleware = OpaqueType.create<{\n public: { $$type: '@backstage/ExtensionPointFactoryMiddleware' };\n versions: {\n readonly version: 'v1';\n readonly extensionPointId: string;\n readonly middleware: (original: unknown) => Promise<unknown>;\n };\n}>({\n type: '@backstage/ExtensionPointFactoryMiddleware',\n versions: ['v1'],\n});\n"],"names":["OpaqueType"],"mappings":";;;;AAkBqDA,sBAAW,MAAA,CAO7D;AAAA,EACD,IAAA,EAAM,4CAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.cjs.js","sources":["../../../../../../../packages/backend-internal/src/wiring/helpers.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { BackendFeature } from '@backstage/backend-plugin-api';\n\n/** @internal */\nexport function isPromise<T>(value: unknown | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function'\n );\n}\n\n/**\n * Unwraps a backend feature from a possibly double-nested default export.\n * This is a workaround where default exports get transpiled to\n * `exports['default'] = ...` in CommonJS modules, which in turn results\n * in a double `{ default: { default: ... } }` nesting when importing\n * using a dynamic import.\n *\n * @internal\n */\nexport function unwrapFeature(\n feature: BackendFeature | { default: BackendFeature },\n): BackendFeature {\n let current: unknown = feature;\n for (let i = 0; i < 2; i++) {\n if (\n current !== null &&\n (typeof current === 'object' || typeof current === 'function')\n ) {\n if ('$$type' in current) {\n return current as BackendFeature;\n }\n if ('default' in current) {\n current = current.default;\n continue;\n }\n }\n break;\n }\n\n return current as BackendFeature;\n}\n"],"names":[],"mappings":";;AAmBO,SAAS,UAAa,KAAA,EAAkD;AAC7E,EAAA,OACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,MAAA,IAAU,KAAA,IACV,OAAO,KAAA,CAAM,IAAA,KAAS,UAAA;AAE1B;;;;"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class OpaqueType {
|
|
4
|
+
/**
|
|
5
|
+
* Creates a new opaque type.
|
|
6
|
+
*
|
|
7
|
+
* @param options.type The type identifier of the opaque type
|
|
8
|
+
* @param options.versions The available versions of the opaque type
|
|
9
|
+
* @returns A new opaque type helper
|
|
10
|
+
*/
|
|
11
|
+
static create(options) {
|
|
12
|
+
return new OpaqueType(options.type, new Set(options.versions));
|
|
13
|
+
}
|
|
14
|
+
#type;
|
|
15
|
+
#versions;
|
|
16
|
+
constructor(type, versions) {
|
|
17
|
+
this.#type = type;
|
|
18
|
+
this.#versions = versions;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
*
|
|
25
|
+
* This property is only useful for type checking, its runtime value is `undefined`.
|
|
26
|
+
*/
|
|
27
|
+
TPublic = void 0;
|
|
28
|
+
/**
|
|
29
|
+
* The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
*
|
|
33
|
+
* This property is only useful for type checking, its runtime value is `undefined`.
|
|
34
|
+
*/
|
|
35
|
+
TInternal = void 0;
|
|
36
|
+
/**
|
|
37
|
+
* @param value Input value expected to be an instance of this opaque type
|
|
38
|
+
* @returns True if the value matches this opaque type
|
|
39
|
+
*/
|
|
40
|
+
isType = (value) => {
|
|
41
|
+
return this.#isThisInternalType(value);
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* @param value Input value expected to be an instance of this opaque type
|
|
45
|
+
* @throws If the value is not an instance of this opaque type or is of an unsupported version
|
|
46
|
+
* @returns The internal version of the opaque type
|
|
47
|
+
*/
|
|
48
|
+
toInternal = (value) => {
|
|
49
|
+
if (!this.#isThisInternalType(value)) {
|
|
50
|
+
throw new TypeError(
|
|
51
|
+
`Invalid opaque type, expected '${this.#type}', but got '${this.#stringifyUnknown(value)}'`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
if (!this.#versions.has(value.version)) {
|
|
55
|
+
const versions = Array.from(this.#versions).map(this.#stringifyVersion);
|
|
56
|
+
if (versions.length > 1) {
|
|
57
|
+
versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;
|
|
58
|
+
}
|
|
59
|
+
const expected = versions.length > 2 ? versions.join(", ") : versions.join(" ");
|
|
60
|
+
throw new TypeError(
|
|
61
|
+
`Invalid opaque type instance, got version ${this.#stringifyVersion(
|
|
62
|
+
value.version
|
|
63
|
+
)}, expected ${expected}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
return value;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Creates an instance of the opaque type, returning the public type.
|
|
70
|
+
*
|
|
71
|
+
* @param version The version of the instance to create
|
|
72
|
+
* @param value The remaining public and internal properties of the instance
|
|
73
|
+
* @returns An instance of the opaque type
|
|
74
|
+
*/
|
|
75
|
+
createInstance(version, props) {
|
|
76
|
+
return Object.assign(props, {
|
|
77
|
+
$$type: this.#type,
|
|
78
|
+
...version && { version }
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
#isThisInternalType(value) {
|
|
82
|
+
if (value === null || typeof value !== "object") {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return value.$$type === this.#type;
|
|
86
|
+
}
|
|
87
|
+
#stringifyUnknown(value) {
|
|
88
|
+
if (typeof value !== "object") {
|
|
89
|
+
return `<${typeof value}>`;
|
|
90
|
+
}
|
|
91
|
+
if (value === null) {
|
|
92
|
+
return "<null>";
|
|
93
|
+
}
|
|
94
|
+
if ("$$type" in value) {
|
|
95
|
+
return String(value.$$type);
|
|
96
|
+
}
|
|
97
|
+
return String(value);
|
|
98
|
+
}
|
|
99
|
+
#stringifyVersion = (version) => {
|
|
100
|
+
return version ? `'${version}'` : "undefined";
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
exports.OpaqueType = OpaqueType;
|
|
105
|
+
//# sourceMappingURL=OpaqueType.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpaqueType.cjs.js","sources":["../../../../../../packages/opaque-internal/src/OpaqueType.ts"],"sourcesContent":["/*\n * Copyright 2024 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\n// TODO(Rugvip): This lives here temporarily, but should be moved to a more\n// central location. It's useful for backend packages too so we'll need to have\n// it in a common package, but it might also be that we want to make it\n// available publicly too in which case it would make sense to have this be part\n// of @backstage/version-bridge. The problem with exporting it from there is\n// that it would need to be very stable at that point, so it might be a bit\n// early to put it there already.\n\n/**\n * A helper for working with opaque types.\n */\nexport class OpaqueType<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n> {\n /**\n * Creates a new opaque type.\n *\n * @param options.type The type identifier of the opaque type\n * @param options.versions The available versions of the opaque type\n * @returns A new opaque type helper\n */\n static create<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n >(options: {\n type: T['public']['$$type'];\n versions: Array<T['versions']['version']>;\n }) {\n return new OpaqueType<T>(options.type, new Set(options.versions));\n }\n\n #type: string;\n #versions: Set<string | undefined>;\n\n private constructor(type: string, versions: Set<string | undefined>) {\n this.#type = type;\n this.#versions = versions;\n }\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TPublic: T['public'] = undefined as any;\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TInternal: T['public'] & T['versions'] = undefined as any;\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @returns True if the value matches this opaque type\n */\n isType = (value: unknown): value is T['public'] => {\n return this.#isThisInternalType(value);\n };\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @throws If the value is not an instance of this opaque type or is of an unsupported version\n * @returns The internal version of the opaque type\n */\n toInternal = (value: unknown): T['public'] & T['versions'] => {\n if (!this.#isThisInternalType(value)) {\n throw new TypeError(\n `Invalid opaque type, expected '${\n this.#type\n }', but got '${this.#stringifyUnknown(value)}'`,\n );\n }\n\n if (!this.#versions.has(value.version)) {\n const versions = Array.from(this.#versions).map(this.#stringifyVersion);\n if (versions.length > 1) {\n versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;\n }\n const expected =\n versions.length > 2 ? versions.join(', ') : versions.join(' ');\n throw new TypeError(\n `Invalid opaque type instance, got version ${this.#stringifyVersion(\n value.version,\n )}, expected ${expected}`,\n );\n }\n\n return value;\n };\n\n /**\n * Creates an instance of the opaque type, returning the public type.\n *\n * @param version The version of the instance to create\n * @param value The remaining public and internal properties of the instance\n * @returns An instance of the opaque type\n */\n createInstance<\n TVersion extends T['versions']['version'],\n TPublic extends T['public'],\n >(\n version: TVersion,\n props: Omit<T['public'], '$$type'> &\n (T['versions'] extends infer UVersion\n ? UVersion extends { version: TVersion }\n ? Omit<UVersion, 'version'>\n : never\n : never) &\n Object, // & Object to allow for object properties too, e.g. toString()\n ): TPublic {\n return Object.assign(props as object, {\n $$type: this.#type,\n ...(version && { version }),\n }) as unknown as TPublic;\n }\n\n #isThisInternalType(value: unknown): value is T['public'] & T['versions'] {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n return (value as T['public']).$$type === this.#type;\n }\n\n #stringifyUnknown(value: unknown) {\n if (typeof value !== 'object') {\n return `<${typeof value}>`;\n }\n if (value === null) {\n return '<null>';\n }\n if ('$$type' in value) {\n return String(value.$$type);\n }\n return String(value);\n }\n\n #stringifyVersion = (version: string | undefined) => {\n return version ? `'${version}'` : 'undefined';\n };\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-permission-node",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.4-next.0",
|
|
4
4
|
"description": "Common permission and authorization utilities for backend plugins",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library",
|
|
@@ -64,10 +64,11 @@
|
|
|
64
64
|
"test": "backstage-cli package test"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@backstage/backend-plugin-api": "1.10.
|
|
67
|
+
"@backstage/backend-plugin-api": "1.10.1-next.0",
|
|
68
68
|
"@backstage/config": "1.3.8",
|
|
69
69
|
"@backstage/errors": "1.3.1",
|
|
70
|
-
"@backstage/plugin-permission-common": "0.9.
|
|
70
|
+
"@backstage/plugin-permission-common": "0.9.10",
|
|
71
|
+
"@standard-schema/spec": "^1.1.0",
|
|
71
72
|
"@types/express": "^4.17.6",
|
|
72
73
|
"express": "^4.22.0",
|
|
73
74
|
"express-promise-router": "^4.1.0",
|
|
@@ -75,11 +76,11 @@
|
|
|
75
76
|
"zod-to-json-schema": "^3.25.1"
|
|
76
77
|
},
|
|
77
78
|
"devDependencies": {
|
|
78
|
-
"@backstage/backend-defaults": "0.17.
|
|
79
|
-
"@backstage/backend-test-utils": "1.11.
|
|
80
|
-
"@backstage/cli": "0.36.
|
|
79
|
+
"@backstage/backend-defaults": "0.17.9-next.0",
|
|
80
|
+
"@backstage/backend-test-utils": "1.11.7-next.0",
|
|
81
|
+
"@backstage/cli": "0.36.6-next.0",
|
|
81
82
|
"@types/supertest": "^2.0.8",
|
|
82
|
-
"msw": "^
|
|
83
|
+
"msw": "^2.0.0",
|
|
83
84
|
"supertest": "^7.0.0"
|
|
84
85
|
}
|
|
85
86
|
}
|