Merge pull request #8784 from backstage/catalog-permission-rule-type-param
catalog-backend: add type parameter to CatalogPermissionRule type
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-permission-node': patch
|
||||
---
|
||||
|
||||
Add helpers for creating PermissionRules with inferred types
|
||||
@@ -306,12 +306,6 @@ export type CatalogEnvironment = {
|
||||
permissions: PermissionAuthorizer;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type CatalogPermissionRule = PermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter
|
||||
>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "CatalogProcessingEngine" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
@@ -528,6 +522,11 @@ export class CommonDatabase implements Database {
|
||||
): Promise<DbEntityResponse>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export const createCatalogPermissionRule: <TParams extends unknown[]>(
|
||||
rule: PermissionRule<Entity, EntitiesSearchFilter, TParams>,
|
||||
) => PermissionRule<Entity, EntitiesSearchFilter, TParams>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "CreateDatabaseOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public @deprecated (undocumented)
|
||||
@@ -1311,7 +1310,13 @@ export class NextCatalogBuilder {
|
||||
addEntityPolicy(...policies: EntityPolicy[]): NextCatalogBuilder;
|
||||
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
|
||||
addEntityProvider(...providers: EntityProvider[]): NextCatalogBuilder;
|
||||
addPermissionRules(...permissionRules: CatalogPermissionRule[]): void;
|
||||
addPermissionRules(
|
||||
...permissionRules: PermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter,
|
||||
unknown[]
|
||||
>[]
|
||||
): void;
|
||||
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
|
||||
addProcessor(...processors: CatalogProcessor[]): NextCatalogBuilder;
|
||||
build(): Promise<{
|
||||
@@ -1359,7 +1364,7 @@ export interface NextRouterOptions {
|
||||
// (undocumented)
|
||||
logger: Logger_2;
|
||||
// (undocumented)
|
||||
permissionRules?: CatalogPermissionRule[];
|
||||
permissionRules?: PermissionRule<Entity, EntitiesSearchFilter, unknown[]>[];
|
||||
// (undocumented)
|
||||
refreshService?: RefreshService;
|
||||
}
|
||||
@@ -1394,12 +1399,28 @@ export function parseEntityYaml(
|
||||
|
||||
// @public
|
||||
export const permissionRules: {
|
||||
hasAnnotation: CatalogPermissionRule;
|
||||
hasLabel: CatalogPermissionRule;
|
||||
hasMetadata: CatalogPermissionRule;
|
||||
hasSpec: CatalogPermissionRule;
|
||||
isEntityKind: CatalogPermissionRule;
|
||||
isEntityOwner: CatalogPermissionRule;
|
||||
hasAnnotation: PermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter,
|
||||
[annotation: string]
|
||||
>;
|
||||
hasLabel: PermissionRule<Entity, EntitiesSearchFilter, [label: string]>;
|
||||
hasMetadata: PermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter,
|
||||
[key: string, value?: string | undefined]
|
||||
>;
|
||||
hasSpec: PermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter,
|
||||
[key: string, value?: string | undefined]
|
||||
>;
|
||||
isEntityKind: PermissionRule<Entity, EntitiesSearchFilter, [kinds: string[]]>;
|
||||
isEntityOwner: PermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter,
|
||||
[claims: string[]]
|
||||
>;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PlaceholderProcessor" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
||||
@@ -15,4 +15,3 @@
|
||||
*/
|
||||
|
||||
export * from './rules';
|
||||
export type { CatalogPermissionRule } from './types';
|
||||
|
||||
@@ -14,15 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { EntitiesSearchFilter } from '../../catalog/types';
|
||||
import { CatalogPermissionRule } from '../types';
|
||||
import { get } from 'lodash';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { createCatalogPermissionRule } from './util';
|
||||
|
||||
export function createPropertyRule(
|
||||
propertyType: 'metadata' | 'spec',
|
||||
): CatalogPermissionRule {
|
||||
return {
|
||||
export const createPropertyRule = (propertyType: 'metadata' | 'spec') =>
|
||||
createCatalogPermissionRule({
|
||||
name: `HAS_${propertyType.toUpperCase()}`,
|
||||
description: `Allow entities which have the specified ${propertyType} subfield.`,
|
||||
apply: (resource: Entity, key: string, value?: string) => {
|
||||
@@ -32,9 +29,8 @@ export function createPropertyRule(
|
||||
}
|
||||
return !!foundValue;
|
||||
},
|
||||
toQuery: (key: string, value?: string): EntitiesSearchFilter => ({
|
||||
toQuery: (key: string, value?: string) => ({
|
||||
key: `${propertyType}.${key}`,
|
||||
...(value !== undefined && { values: [value] }),
|
||||
}),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,21 +15,21 @@
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { EntitiesSearchFilter } from '../../catalog/types';
|
||||
import { CatalogPermissionRule } from '../types';
|
||||
import { createCatalogPermissionRule } from './util';
|
||||
|
||||
/**
|
||||
* A {@link CatalogPermissionRule} which filters for the presence of an
|
||||
* annotation on a given entity.
|
||||
* A catalog {@link @backstage/plugin-permission-node#PermissionRule} which
|
||||
* filters for the presence of an annotation on a given entity.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const hasAnnotation: CatalogPermissionRule = {
|
||||
export const hasAnnotation = createCatalogPermissionRule({
|
||||
name: 'HAS_ANNOTATION',
|
||||
description:
|
||||
'Allow entities which are annotated with the specified annotation',
|
||||
apply: (resource: Entity, annotation: string) =>
|
||||
!!resource.metadata.annotations?.hasOwnProperty(annotation),
|
||||
toQuery: (annotation: string): EntitiesSearchFilter => ({
|
||||
toQuery: (annotation: string) => ({
|
||||
key: `metadata.annotations.${annotation}`,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -15,20 +15,19 @@
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { EntitiesSearchFilter } from '../../catalog/types';
|
||||
import { CatalogPermissionRule } from '../types';
|
||||
import { createCatalogPermissionRule } from './util';
|
||||
|
||||
/**
|
||||
* A {@link CatalogPermissionRule} which filters for entities with a specified
|
||||
* label in its metadata.
|
||||
* A catalog {@link @backstage/plugin-permission-node#PermissionRule} which
|
||||
* filters for entities with a specified label in its metadata.
|
||||
* @public
|
||||
*/
|
||||
export const hasLabel: CatalogPermissionRule = {
|
||||
export const hasLabel = createCatalogPermissionRule({
|
||||
name: 'HAS_LABEL',
|
||||
description: 'Allow entities which have the specified label metadata.',
|
||||
apply: (resource: Entity, label: string) =>
|
||||
!!resource.metadata.labels?.hasOwnProperty(label),
|
||||
toQuery: (label: string): EntitiesSearchFilter => ({
|
||||
toQuery: (label: string) => ({
|
||||
key: `metadata.labels.${label}`,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
import { createPropertyRule } from './createPropertyRule';
|
||||
|
||||
/**
|
||||
* A {@link CatalogPermissionRule} which filters for entities with the specified
|
||||
* metadata subfield. Also matches on values if value is provided.
|
||||
* A catalog {@link @backstage/plugin-permission-node#PermissionRule} which
|
||||
* filters for entities with the specified metadata subfield. Also matches on
|
||||
* values if value is provided.
|
||||
*
|
||||
* The key argument to the `apply` and `toQuery` methods can be nested, such as
|
||||
* 'field.nestedfield'.
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
import { createPropertyRule } from './createPropertyRule';
|
||||
|
||||
/**
|
||||
* A {@link CatalogPermissionRule} which filters for entities with the specified
|
||||
* spec subfield. Also matches on values if value is provided.
|
||||
* A catalog {@link @backstage/plugin-permission-node#PermissionRule} which
|
||||
* filters for entities with the specified spec subfield. Also matches on values
|
||||
* if value is provided.
|
||||
*
|
||||
* The key argument to the `apply` and `toQuery` methods can be nested, such as
|
||||
* 'field.nestedfield'.
|
||||
|
||||
@@ -34,3 +34,5 @@ export const permissionRules = {
|
||||
isEntityKind,
|
||||
isEntityOwner,
|
||||
};
|
||||
|
||||
export { createCatalogPermissionRule } from './util';
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { EntitiesSearchFilter } from '../../catalog/types';
|
||||
import { CatalogPermissionRule } from '../types';
|
||||
import { createCatalogPermissionRule } from './util';
|
||||
|
||||
/**
|
||||
* A {@link CatalogPermissionRule} which filters for entities with a specified
|
||||
* kind.
|
||||
* A catalog {@link @backstage/plugin-permission-node#PermissionRule} which
|
||||
* filters for entities with a specified kind.
|
||||
* @public
|
||||
*/
|
||||
export const isEntityKind: CatalogPermissionRule = {
|
||||
export const isEntityKind = createCatalogPermissionRule({
|
||||
name: 'IS_ENTITY_KIND',
|
||||
description: 'Allow entities with the specified kind',
|
||||
apply(resource: Entity, kinds: string[]) {
|
||||
@@ -35,4 +35,4 @@ export const isEntityKind: CatalogPermissionRule = {
|
||||
values: kinds.map(kind => kind.toLocaleLowerCase('en-US')),
|
||||
};
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -19,15 +19,14 @@ import {
|
||||
RELATION_OWNED_BY,
|
||||
stringifyEntityRef,
|
||||
} from '@backstage/catalog-model';
|
||||
import { EntitiesSearchFilter } from '../../catalog/types';
|
||||
import { CatalogPermissionRule } from '../types';
|
||||
import { createCatalogPermissionRule } from './util';
|
||||
|
||||
/**
|
||||
* A {@link CatalogPermissionRule} which filters for entities with a specified
|
||||
* owner.
|
||||
* A catalog {@link @backstage/plugin-permission-node#PermissionRule} which
|
||||
* filters for entities with a specified owner.
|
||||
* @public
|
||||
*/
|
||||
export const isEntityOwner: CatalogPermissionRule = {
|
||||
export const isEntityOwner = createCatalogPermissionRule({
|
||||
name: 'IS_ENTITY_OWNER',
|
||||
description: 'Allow entities owned by the current user',
|
||||
apply: (resource: Entity, claims: string[]) => {
|
||||
@@ -39,8 +38,8 @@ export const isEntityOwner: CatalogPermissionRule = {
|
||||
.filter(relation => relation.type === RELATION_OWNED_BY)
|
||||
.some(relation => claims.includes(stringifyEntityRef(relation.target)));
|
||||
},
|
||||
toQuery: (claims: string[]): EntitiesSearchFilter => ({
|
||||
toQuery: (claims: string[]) => ({
|
||||
key: 'relations.ownedBy',
|
||||
values: claims,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
+9
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
* Copyright 2022 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.
|
||||
@@ -13,18 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { PermissionRule } from '@backstage/plugin-permission-node';
|
||||
import { EntitiesSearchFilter } from '../catalog/types';
|
||||
import { makeCreatePermissionRule } from '@backstage/plugin-permission-node';
|
||||
import { EntitiesSearchFilter } from '../../catalog/types';
|
||||
|
||||
/**
|
||||
* A conditional rule that can be used to filter catalog entities for an
|
||||
* authorization request. See
|
||||
* {@link @backstage/plugin-permission-node#PermissionRule} for more details.
|
||||
* Helper function for creating correctly-typed
|
||||
* {@link @backstage/plugin-permission-node#PermissionRule}s for the
|
||||
* catalog-backend.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CatalogPermissionRule = PermissionRule<
|
||||
export const createCatalogPermissionRule = makeCreatePermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter
|
||||
>;
|
||||
>();
|
||||
@@ -17,6 +17,7 @@
|
||||
import { PluginDatabaseManager, UrlReader } from '@backstage/backend-common';
|
||||
import {
|
||||
DefaultNamespaceEntityPolicy,
|
||||
Entity,
|
||||
EntityPolicies,
|
||||
EntityPolicy,
|
||||
FieldFormatEntityPolicy,
|
||||
@@ -29,7 +30,7 @@ import { ScmIntegrations } from '@backstage/integration';
|
||||
import { createHash } from 'crypto';
|
||||
import { Router } from 'express';
|
||||
import lodash from 'lodash';
|
||||
import { EntitiesCatalog } from '../catalog';
|
||||
import { EntitiesCatalog, EntitiesSearchFilter } from '../catalog';
|
||||
import {
|
||||
DatabaseLocationsCatalog,
|
||||
LocationsCatalog,
|
||||
@@ -83,9 +84,9 @@ import { Config } from '@backstage/config';
|
||||
import { Logger } from 'winston';
|
||||
import { LocationService } from './types';
|
||||
import { connectEntityProviders } from '../processing/connectEntityProviders';
|
||||
import { CatalogPermissionRule } from '../permissions/types';
|
||||
import { permissionRules as catalogPermissionRules } from '../permissions/rules';
|
||||
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
|
||||
import { PermissionRule } from '@backstage/plugin-permission-node';
|
||||
|
||||
export type CatalogEnvironment = {
|
||||
logger: Logger;
|
||||
@@ -130,7 +131,11 @@ export class NextCatalogBuilder {
|
||||
maxSeconds: 150,
|
||||
});
|
||||
private locationAnalyzer: LocationAnalyzer | undefined = undefined;
|
||||
private permissionRules: CatalogPermissionRule[];
|
||||
private permissionRules: PermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter,
|
||||
unknown[]
|
||||
>[];
|
||||
|
||||
constructor(env: CatalogEnvironment) {
|
||||
this.env = env;
|
||||
@@ -331,7 +336,13 @@ export class NextCatalogBuilder {
|
||||
*
|
||||
* @param permissionRules - Additional permission rules
|
||||
*/
|
||||
addPermissionRules(...permissionRules: CatalogPermissionRule[]) {
|
||||
addPermissionRules(
|
||||
...permissionRules: PermissionRule<
|
||||
Entity,
|
||||
EntitiesSearchFilter,
|
||||
unknown[]
|
||||
>[]
|
||||
) {
|
||||
this.permissionRules.push(...permissionRules);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,14 +25,16 @@ import {
|
||||
import { Config } from '@backstage/config';
|
||||
import { NotFoundError } from '@backstage/errors';
|
||||
import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common';
|
||||
import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';
|
||||
import {
|
||||
createPermissionIntegrationRouter,
|
||||
PermissionRule,
|
||||
} from '@backstage/plugin-permission-node';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { Logger } from 'winston';
|
||||
import yn from 'yn';
|
||||
import { EntitiesCatalog } from '../catalog';
|
||||
import { EntitiesCatalog, EntitiesSearchFilter } from '../catalog';
|
||||
import { LocationAnalyzer } from '../ingestion/types';
|
||||
import { CatalogPermissionRule } from '../permissions/types';
|
||||
import {
|
||||
basicEntityFilter,
|
||||
parseEntityFilterParams,
|
||||
@@ -49,7 +51,7 @@ export interface NextRouterOptions {
|
||||
refreshService?: RefreshService;
|
||||
logger: Logger;
|
||||
config: Config;
|
||||
permissionRules?: CatalogPermissionRule[];
|
||||
permissionRules?: PermissionRule<Entity, EntitiesSearchFilter, unknown[]>[];
|
||||
}
|
||||
|
||||
export async function createNextRouter(
|
||||
|
||||
@@ -95,6 +95,22 @@ export const createPermissionIntegrationRouter: <TResource>(options: {
|
||||
getResource: (resourceRef: string) => Promise<TResource | undefined>;
|
||||
}) => Router;
|
||||
|
||||
// @public
|
||||
export const createPermissionRule: <
|
||||
TResource,
|
||||
TQuery,
|
||||
TParams extends unknown[],
|
||||
>(
|
||||
rule: PermissionRule<TResource, TQuery, TParams>,
|
||||
) => PermissionRule<TResource, TQuery, TParams>;
|
||||
|
||||
// @public
|
||||
export const makeCreatePermissionRule: <TResource, TQuery>() => <
|
||||
TParams extends unknown[],
|
||||
>(
|
||||
rule: PermissionRule<TResource, TQuery, TParams>,
|
||||
) => PermissionRule<TResource, TQuery, TParams>;
|
||||
|
||||
// @public
|
||||
export interface PermissionPolicy {
|
||||
// (undocumented)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PermissionRule } from '../types';
|
||||
|
||||
/**
|
||||
* Helper function to ensure that {@link PermissionRule} definitions are typed correctly.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const createPermissionRule = <
|
||||
TResource,
|
||||
TQuery,
|
||||
TParams extends unknown[],
|
||||
>(
|
||||
rule: PermissionRule<TResource, TQuery, TParams>,
|
||||
) => rule;
|
||||
|
||||
/**
|
||||
* Helper for making plugin-specific createPermissionRule functions, that have
|
||||
* the TResource and TQuery type parameters populated but infer the params from
|
||||
* the supplied rule. This helps ensure that rules created for this plugin use
|
||||
* consistent types for the resource and query.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const makeCreatePermissionRule =
|
||||
<TResource, TQuery>() =>
|
||||
<TParams extends unknown[]>(
|
||||
rule: PermissionRule<TResource, TQuery, TParams>,
|
||||
) =>
|
||||
createPermissionRule(rule);
|
||||
@@ -18,3 +18,4 @@ export * from './createConditionFactory';
|
||||
export * from './createConditionExports';
|
||||
export * from './createConditionTransformer';
|
||||
export * from './createPermissionIntegrationRouter';
|
||||
export * from './createPermissionRule';
|
||||
|
||||
Reference in New Issue
Block a user