permission-node: add PermissionResourceRef
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-permission-node': patch
|
||||
---
|
||||
|
||||
Added a new `createPermissionResourceRef` utility that encapsulates the constants and types related to a permission resource types. The `createConditionExports` and `createPermissionRule` functions have also been adapted to accept these references as arguments, deprecating their older counterparts.
|
||||
@@ -83,7 +83,23 @@ export const createConditionAuthorizer: <TResource, TQuery>(
|
||||
) => (decision: PolicyDecision, resource: TResource | undefined) => boolean;
|
||||
|
||||
// @public
|
||||
export const createConditionExports: <
|
||||
export function createConditionExports<
|
||||
TResourceType extends string,
|
||||
TResource,
|
||||
TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,
|
||||
>(options: {
|
||||
resourceRef: PermissionResourceRef<TResource, any, TResourceType>;
|
||||
rules: TRules;
|
||||
}): {
|
||||
conditions: Conditions<TRules>;
|
||||
createConditionalDecision: (
|
||||
permission: ResourcePermission<TResourceType>,
|
||||
conditions: PermissionCriteria<PermissionCondition<TResourceType>>,
|
||||
) => ConditionalPolicyDecision;
|
||||
};
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export function createConditionExports<
|
||||
TResourceType extends string,
|
||||
TResource,
|
||||
TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,
|
||||
@@ -91,7 +107,7 @@ export const createConditionExports: <
|
||||
pluginId: string;
|
||||
resourceType: TResourceType;
|
||||
rules: TRules;
|
||||
}) => {
|
||||
}): {
|
||||
conditions: Conditions<TRules>;
|
||||
createConditionalDecision: (
|
||||
permission: ResourcePermission<TResourceType>,
|
||||
@@ -164,15 +180,48 @@ export type CreatePermissionIntegrationRouterResourceOptions<
|
||||
) => Promise<Array<TResource | undefined>>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export function createPermissionResourceRef<TResource, TQuery>(): {
|
||||
with<TPluginId extends string, TResourceType extends string>(options: {
|
||||
pluginId: TPluginId;
|
||||
resourceType: TResourceType;
|
||||
}): PermissionResourceRef<TResource, TQuery, TResourceType, TPluginId>;
|
||||
};
|
||||
|
||||
// @public
|
||||
export const createPermissionRule: <
|
||||
export function createPermissionRule<
|
||||
TResource,
|
||||
TQuery,
|
||||
TResourceType extends string,
|
||||
TParams extends PermissionRuleParams = undefined,
|
||||
>(
|
||||
rule: CreatePermissionRuleOptions<TResource, TQuery, TResourceType, TParams>,
|
||||
): PermissionRule<TResource, TQuery, TResourceType, TParams>;
|
||||
|
||||
// @public @deprecated
|
||||
export function createPermissionRule<
|
||||
TResource,
|
||||
TQuery,
|
||||
TResourceType extends string,
|
||||
TParams extends PermissionRuleParams = undefined,
|
||||
>(
|
||||
rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,
|
||||
) => PermissionRule<TResource, TQuery, TResourceType, TParams>;
|
||||
): PermissionRule<TResource, TQuery, TResourceType, TParams>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type CreatePermissionRuleOptions<
|
||||
TResource,
|
||||
TQuery,
|
||||
TResourceType extends string,
|
||||
TParams extends PermissionRuleParams = PermissionRuleParams,
|
||||
> = {
|
||||
name: string;
|
||||
description: string;
|
||||
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>;
|
||||
paramsSchema?: z.ZodSchema<TParams>;
|
||||
apply(resource: TResource, params: NoInfer_2<TParams>): boolean;
|
||||
toQuery(params: NoInfer_2<TParams>): PermissionCriteria<TQuery>;
|
||||
};
|
||||
|
||||
// @public
|
||||
export const isAndCriteria: <T>(
|
||||
@@ -189,7 +238,7 @@ export const isOrCriteria: <T>(
|
||||
criteria: PermissionCriteria<T>,
|
||||
) => criteria is AnyOfCriteria<T>;
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export const makeCreatePermissionRule: <
|
||||
TResource,
|
||||
TQuery,
|
||||
@@ -253,6 +302,20 @@ export interface PermissionPolicy {
|
||||
handle(request: PolicyQuery, user?: PolicyQueryUser): Promise<PolicyDecision>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type PermissionResourceRef<
|
||||
TResource = unknown,
|
||||
TQuery = unknown,
|
||||
TResourceType extends string = string,
|
||||
TPluginId extends string = string,
|
||||
> = {
|
||||
readonly $$type: '@backstage/PermissionResourceRef';
|
||||
readonly pluginId: TPluginId;
|
||||
readonly resourceType: TResourceType;
|
||||
readonly TQuery: TQuery;
|
||||
readonly TResource: TResource;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type PermissionRule<
|
||||
TResource,
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
} from '@backstage/plugin-permission-common';
|
||||
import { PermissionRule } from '../types';
|
||||
import { createConditionFactory } from './createConditionFactory';
|
||||
import { PermissionResourceRef } from './createPermissionResourceRef';
|
||||
|
||||
/**
|
||||
* A utility type for mapping a single {@link PermissionRule} to its
|
||||
@@ -73,7 +74,25 @@ export type Conditions<
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const createConditionExports = <
|
||||
export function createConditionExports<
|
||||
TResourceType extends string,
|
||||
TResource,
|
||||
TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,
|
||||
>(options: {
|
||||
resourceRef: PermissionResourceRef<TResource, any, TResourceType>;
|
||||
rules: TRules;
|
||||
}): {
|
||||
conditions: Conditions<TRules>;
|
||||
createConditionalDecision: (
|
||||
permission: ResourcePermission<TResourceType>,
|
||||
conditions: PermissionCriteria<PermissionCondition<TResourceType>>,
|
||||
) => ConditionalPolicyDecision;
|
||||
};
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use the version of `createConditionExports` that accepts a `resourceRef` option instead.
|
||||
*/
|
||||
export function createConditionExports<
|
||||
TResourceType extends string,
|
||||
TResource,
|
||||
TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,
|
||||
@@ -87,8 +106,32 @@ export const createConditionExports = <
|
||||
permission: ResourcePermission<TResourceType>,
|
||||
conditions: PermissionCriteria<PermissionCondition<TResourceType>>,
|
||||
) => ConditionalPolicyDecision;
|
||||
} => {
|
||||
const { pluginId, resourceType, rules } = options;
|
||||
};
|
||||
export function createConditionExports<
|
||||
TResourceType extends string,
|
||||
TResource,
|
||||
TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,
|
||||
>(
|
||||
options:
|
||||
| {
|
||||
resourceRef: PermissionResourceRef<TResource, any, TResourceType>;
|
||||
rules: TRules;
|
||||
}
|
||||
| {
|
||||
pluginId: string;
|
||||
resourceType: TResourceType;
|
||||
rules: TRules;
|
||||
},
|
||||
): {
|
||||
conditions: Conditions<TRules>;
|
||||
createConditionalDecision: (
|
||||
permission: ResourcePermission<TResourceType>,
|
||||
conditions: PermissionCriteria<PermissionCondition<TResourceType>>,
|
||||
) => ConditionalPolicyDecision;
|
||||
} {
|
||||
const { rules } = options;
|
||||
const { pluginId, resourceType } =
|
||||
'resourceRef' in options ? options.resourceRef : options;
|
||||
|
||||
return {
|
||||
conditions: Object.entries(rules).reduce(
|
||||
@@ -108,4 +151,4 @@ export const createConditionExports = <
|
||||
conditions,
|
||||
}),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import { PermissionRule } from '../types';
|
||||
* The rule itself defines _how_ to check a given resource, whereas a condition also includes _what_
|
||||
* to verify.
|
||||
*
|
||||
* Plugin authors should generally use the {@link createConditionExports} in order to efficiently
|
||||
* Plugin authors should generally use the {@link (createConditionExports:1)} in order to efficiently
|
||||
* create multiple condition factories. This helper should generally only be used to construct
|
||||
* condition factories for third-party rules that aren't part of the backend plugin with which
|
||||
* they're intended to integrate.
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
isOrCriteria,
|
||||
} from './util';
|
||||
import { NotImplementedError } from '@backstage/errors';
|
||||
import { PermissionResourceRef } from './createPermissionResourceRef';
|
||||
|
||||
const permissionCriteriaSchema: z.ZodSchema<
|
||||
PermissionCriteria<PermissionCondition>
|
||||
@@ -163,10 +164,22 @@ const applyConditions = <TResourceType extends string, TResource>(
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const createConditionAuthorizer = <TResource, TQuery>(
|
||||
export function createConditionAuthorizer<TResource>(
|
||||
permissionRuleAccessor: PermissionRuleAccessor<TResource>,
|
||||
): (decision: PolicyDecision, resource: TResource | undefined) => boolean;
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use the version of `createConditionAuthorizer` that accepts a `PermissionRuleAccessor` instead.
|
||||
*/
|
||||
export function createConditionAuthorizer<TResource, TQuery>(
|
||||
rules: PermissionRule<TResource, TQuery, string>[],
|
||||
) => {
|
||||
const getRule = createGetRule(rules);
|
||||
): (decision: PolicyDecision, resource: TResource | undefined) => boolean;
|
||||
export function createConditionAuthorizer<TResource, TQuery>(
|
||||
rules:
|
||||
| PermissionRule<TResource, TQuery, string>[]
|
||||
| PermissionRuleAccessor<TResource>,
|
||||
): (decision: PolicyDecision, resource: TResource | undefined) => boolean {
|
||||
const getRule = typeof rules === 'function' ? rules : createGetRule(rules);
|
||||
|
||||
return (
|
||||
decision: PolicyDecision,
|
||||
@@ -178,7 +191,7 @@ export const createConditionAuthorizer = <TResource, TQuery>(
|
||||
|
||||
return decision.result === AuthorizeResult.ALLOW;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for creating a permission integration router specific
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type PermissionResourceRef<
|
||||
TResource = unknown,
|
||||
TQuery = unknown,
|
||||
TResourceType extends string = string,
|
||||
TPluginId extends string = string,
|
||||
> = {
|
||||
readonly $$type: '@backstage/PermissionResourceRef';
|
||||
readonly pluginId: TPluginId;
|
||||
readonly resourceType: TResourceType;
|
||||
readonly TQuery: TQuery;
|
||||
readonly TResource: TResource;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function createPermissionResourceRef<TResource, TQuery>(): {
|
||||
with<TPluginId extends string, TResourceType extends string>(options: {
|
||||
pluginId: TPluginId;
|
||||
resourceType: TResourceType;
|
||||
}): PermissionResourceRef<TResource, TQuery, TResourceType, TPluginId>;
|
||||
} {
|
||||
return {
|
||||
with<TPluginId extends string, TResourceType extends string>(options: {
|
||||
pluginId: TPluginId;
|
||||
resourceType: TResourceType;
|
||||
}): PermissionResourceRef<TResource, TQuery, TResourceType, TPluginId> {
|
||||
return {
|
||||
$$type: '@backstage/PermissionResourceRef',
|
||||
pluginId: options.pluginId,
|
||||
resourceType: options.resourceType,
|
||||
TQuery: null as TQuery,
|
||||
TResource: null as TResource,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -14,22 +14,91 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PermissionRuleParams } from '@backstage/plugin-permission-common';
|
||||
import {
|
||||
PermissionCriteria,
|
||||
PermissionRuleParams,
|
||||
} from '@backstage/plugin-permission-common';
|
||||
import { PermissionRule } from '../types';
|
||||
import { z } from 'zod';
|
||||
import { PermissionResourceRef } from './createPermissionResourceRef';
|
||||
import { NoInfer } from './util';
|
||||
|
||||
/**
|
||||
* Helper function to ensure that {@link PermissionRule} definitions are typed correctly.
|
||||
* @public
|
||||
*/
|
||||
export type CreatePermissionRuleOptions<
|
||||
TResource,
|
||||
TQuery,
|
||||
TResourceType extends string,
|
||||
TParams extends PermissionRuleParams = PermissionRuleParams,
|
||||
> = {
|
||||
name: string;
|
||||
description: string;
|
||||
|
||||
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>;
|
||||
|
||||
/**
|
||||
* A ZodSchema that reflects the structure of the parameters that are passed to
|
||||
*/
|
||||
paramsSchema?: z.ZodSchema<TParams>;
|
||||
|
||||
/**
|
||||
* Apply this rule to a resource already loaded from a backing data source. The params are
|
||||
* arguments supplied for the rule; for example, a rule could be `isOwner` with entityRefs as the
|
||||
* params.
|
||||
*/
|
||||
apply(resource: TResource, params: NoInfer<TParams>): boolean;
|
||||
|
||||
/**
|
||||
* Translate this rule to criteria suitable for use in querying a backing data store. The criteria
|
||||
* can be used for loading a collection of resources efficiently with conditional criteria already
|
||||
* applied.
|
||||
*/
|
||||
toQuery(params: NoInfer<TParams>): PermissionCriteria<TQuery>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to create a {@link PermissionRule} for a specific resource type using a {@link PermissionResourceRef}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const createPermissionRule = <
|
||||
export function createPermissionRule<
|
||||
TResource,
|
||||
TQuery,
|
||||
TResourceType extends string,
|
||||
TParams extends PermissionRuleParams = undefined,
|
||||
>(
|
||||
rule: CreatePermissionRuleOptions<TResource, TQuery, TResourceType, TParams>,
|
||||
): PermissionRule<TResource, TQuery, TResourceType, TParams>;
|
||||
/**
|
||||
* Helper function to ensure that {@link PermissionRule} definitions are typed correctly.
|
||||
*
|
||||
* @deprecated Use the version of `createPermissionRule` that accepts a `resourceRef` option instead.
|
||||
* @public
|
||||
*/
|
||||
export function createPermissionRule<
|
||||
TResource,
|
||||
TQuery,
|
||||
TResourceType extends string,
|
||||
TParams extends PermissionRuleParams = undefined,
|
||||
>(
|
||||
rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,
|
||||
) => rule;
|
||||
): PermissionRule<TResource, TQuery, TResourceType, TParams>;
|
||||
export function createPermissionRule<
|
||||
TResource,
|
||||
TQuery,
|
||||
TResourceType extends string,
|
||||
TParams extends PermissionRuleParams = undefined,
|
||||
>(
|
||||
rule:
|
||||
| PermissionRule<TResource, TQuery, TResourceType, TParams>
|
||||
| CreatePermissionRuleOptions<TResource, TQuery, TResourceType, TParams>,
|
||||
): PermissionRule<TResource, TQuery, TResourceType, TParams> {
|
||||
if ('resourceRef' in rule) {
|
||||
return { ...rule, resourceType: rule.resourceRef.resourceType };
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for making plugin-specific createPermissionRule functions, that have
|
||||
@@ -38,6 +107,7 @@ export const createPermissionRule = <
|
||||
* consistent types for the resource and query.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link (createPermissionRule:1)} directly instead with the resourceRef option.
|
||||
*/
|
||||
export const makeCreatePermissionRule =
|
||||
<TResource, TQuery, TResourceType extends string>() =>
|
||||
|
||||
@@ -19,4 +19,8 @@ export * from './createConditionExports';
|
||||
export * from './createConditionTransformer';
|
||||
export * from './createPermissionIntegrationRouter';
|
||||
export * from './createPermissionRule';
|
||||
export {
|
||||
createPermissionResourceRef,
|
||||
type PermissionResourceRef,
|
||||
} from './createPermissionResourceRef';
|
||||
export { isAndCriteria, isOrCriteria, isNotCriteria } from './util';
|
||||
|
||||
Reference in New Issue
Block a user