fix permissions being overwritten by the unprocessed entities module
Co-authored-by: Vincenzo Scamporlino <vincenzos@spotify.com> Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
'@backstage/plugin-catalog-node': minor
|
||||
---
|
||||
|
||||
Added the ability to inject custom permissions from modules, on `CatalogBuilder` and `CatalogPermissionExtensionPoint`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-unprocessed': patch
|
||||
---
|
||||
|
||||
Internal update that injects custom permissions into the catalog using its extension point
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-permission-backend': patch
|
||||
---
|
||||
|
||||
Properly forward causes of errors from upstream backends in the `PermissionIntegrationClient`
|
||||
@@ -40,6 +40,7 @@
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/plugin-auth-node": "workspace:^",
|
||||
"@backstage/plugin-catalog-node": "workspace:^",
|
||||
"@backstage/plugin-catalog-unprocessed-entities-common": "workspace:^",
|
||||
"@backstage/plugin-permission-common": "workspace:^",
|
||||
"@backstage/plugin-permission-node": "workspace:^",
|
||||
|
||||
@@ -34,7 +34,6 @@ import {
|
||||
AuthorizeResult,
|
||||
BasicPermission,
|
||||
} from '@backstage/plugin-permission-common';
|
||||
import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';
|
||||
import { unprocessedEntitiesDeletePermission } from '@backstage/plugin-catalog-unprocessed-entities-common';
|
||||
import { NotAllowedError } from '@backstage/errors';
|
||||
import { createLegacyAuthAdapters } from '@backstage/backend-common';
|
||||
@@ -145,10 +144,6 @@ export class UnprocessedEntitiesModule {
|
||||
}
|
||||
|
||||
registerRoutes() {
|
||||
const permissionIntegrationRouter = createPermissionIntegrationRouter({
|
||||
permissions: [unprocessedEntitiesDeletePermission],
|
||||
});
|
||||
|
||||
const isRequestAuthorized = async (
|
||||
req: Request,
|
||||
permission: BasicPermission,
|
||||
@@ -162,8 +157,6 @@ export class UnprocessedEntitiesModule {
|
||||
return decision.result !== AuthorizeResult.DENY;
|
||||
};
|
||||
|
||||
this.router.use(permissionIntegrationRouter);
|
||||
|
||||
this.moduleRouter
|
||||
.get('/entities/unprocessed/failed', async (req, res) => {
|
||||
return res.json(
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
createBackendModule,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { UnprocessedEntitiesModule } from './UnprocessedEntitiesModule';
|
||||
import { catalogPermissionExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
|
||||
import { unprocessedEntitiesDeletePermission } from '@backstage/plugin-catalog-unprocessed-entities-common';
|
||||
|
||||
/**
|
||||
* Catalog Module for Unprocessed Entities
|
||||
@@ -37,6 +39,7 @@ export const catalogModuleUnprocessedEntities = createBackendModule({
|
||||
httpAuth: coreServices.httpAuth,
|
||||
discovery: coreServices.discovery,
|
||||
permissions: coreServices.permissions,
|
||||
catalogPermissions: catalogPermissionExtensionPoint,
|
||||
},
|
||||
async init({
|
||||
database,
|
||||
@@ -45,6 +48,7 @@ export const catalogModuleUnprocessedEntities = createBackendModule({
|
||||
permissions,
|
||||
httpAuth,
|
||||
discovery,
|
||||
catalogPermissions,
|
||||
}) {
|
||||
const module = UnprocessedEntitiesModule.create({
|
||||
database: await database.getClient(),
|
||||
@@ -54,6 +58,8 @@ export const catalogModuleUnprocessedEntities = createBackendModule({
|
||||
httpAuth,
|
||||
});
|
||||
|
||||
catalogPermissions.addPermissions(unprocessedEntitiesDeletePermission);
|
||||
|
||||
module.registerRoutes();
|
||||
|
||||
logger.info(
|
||||
|
||||
@@ -148,6 +148,7 @@ export class CatalogBuilder {
|
||||
CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>
|
||||
>
|
||||
): this;
|
||||
addPermissions(...permissions: Array<Permission | Array<Permission>>): this;
|
||||
addProcessor(
|
||||
...processors: Array<CatalogProcessor_2 | Array<CatalogProcessor_2>>
|
||||
): CatalogBuilder;
|
||||
|
||||
@@ -84,7 +84,10 @@ import { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';
|
||||
import { Config, readDurationFromConfig } from '@backstage/config';
|
||||
import { Logger } from 'winston';
|
||||
import { connectEntityProviders } from '../processing/connectEntityProviders';
|
||||
import { PermissionRuleParams } from '@backstage/plugin-permission-common';
|
||||
import {
|
||||
Permission,
|
||||
PermissionRuleParams,
|
||||
} from '@backstage/plugin-permission-common';
|
||||
import { permissionRules as catalogPermissionRules } from '../permissions/rules';
|
||||
import { PermissionRule } from '@backstage/plugin-permission-node';
|
||||
import {
|
||||
@@ -177,6 +180,7 @@ export class CatalogBuilder {
|
||||
}) => Promise<void> | void;
|
||||
private processingInterval: ProcessingIntervalFunction;
|
||||
private locationAnalyzer: LocationAnalyzer | undefined = undefined;
|
||||
private readonly permissions: Permission[];
|
||||
private readonly permissionRules: CatalogPermissionRuleInput[];
|
||||
private allowedLocationType: string[];
|
||||
private legacySingleProcessorValidation = false;
|
||||
@@ -200,6 +204,7 @@ export class CatalogBuilder {
|
||||
this.locationAnalyzers = [];
|
||||
this.processorsReplace = false;
|
||||
this.parser = undefined;
|
||||
this.permissions = [...catalogPermissions];
|
||||
this.permissionRules = Object.values(catalogPermissionRules);
|
||||
this.allowedLocationType = ['url'];
|
||||
|
||||
@@ -401,6 +406,17 @@ export class CatalogBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds additional permissions. See
|
||||
* {@link @backstage/plugin-permission-node#Permission}.
|
||||
*
|
||||
* @param permissions - Additional permissions
|
||||
*/
|
||||
addPermissions(...permissions: Array<Permission | Array<Permission>>) {
|
||||
this.permissions.push(...permissions.flat());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds additional permission rules. Permission rules are used to evaluate
|
||||
* catalog resources against queries. See
|
||||
@@ -551,7 +567,7 @@ export class CatalogBuilder {
|
||||
entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],
|
||||
);
|
||||
},
|
||||
permissions: catalogPermissions,
|
||||
permissions: this.permissions,
|
||||
rules: this.permissionRules,
|
||||
});
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
} from '@backstage/plugin-catalog-node';
|
||||
import { loggerToWinstonLogger } from '@backstage/backend-common';
|
||||
import { merge } from 'lodash';
|
||||
import { Permission } from '@backstage/plugin-permission-common';
|
||||
|
||||
class CatalogProcessingExtensionPointImpl
|
||||
implements CatalogProcessingExtensionPoint
|
||||
@@ -113,8 +114,13 @@ class CatalogAnalysisExtensionPointImpl
|
||||
class CatalogPermissionExtensionPointImpl
|
||||
implements CatalogPermissionExtensionPoint
|
||||
{
|
||||
#permissions = new Array<Permission>();
|
||||
#permissionRules = new Array<CatalogPermissionRuleInput>();
|
||||
|
||||
addPermissions(...permission: Array<Permission | Array<Permission>>): void {
|
||||
this.#permissions.push(...permission.flat());
|
||||
}
|
||||
|
||||
addPermissionRules(
|
||||
...rules: Array<
|
||||
CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>
|
||||
@@ -123,6 +129,10 @@ class CatalogPermissionExtensionPointImpl
|
||||
this.#permissionRules.push(...rules.flat());
|
||||
}
|
||||
|
||||
get permissions() {
|
||||
return this.#permissions;
|
||||
}
|
||||
|
||||
get permissionRules() {
|
||||
return this.#permissionRules;
|
||||
}
|
||||
@@ -239,6 +249,7 @@ export const catalogPlugin = createBackendPlugin({
|
||||
([key, resolver]) => builder.setPlaceholderResolver(key, resolver),
|
||||
);
|
||||
builder.addLocationAnalyzers(...analysisExtensions.locationAnalyzers);
|
||||
builder.addPermissions(...permissionExtensions.permissions);
|
||||
builder.addPermissionRules(...permissionExtensions.permissionRules);
|
||||
builder.setFieldFormatValidators(modelExtensions.fieldValidators);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { EntitiesSearchFilter } from '@backstage/plugin-catalog-node';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-node';
|
||||
import { ExtensionPoint } from '@backstage/backend-plugin-api';
|
||||
import { Permission } from '@backstage/plugin-permission-common';
|
||||
import { PermissionRule } from '@backstage/plugin-permission-node';
|
||||
import { PermissionRuleParams } from '@backstage/plugin-permission-common';
|
||||
import { PlaceholderResolver } from '@backstage/plugin-catalog-node';
|
||||
@@ -43,6 +44,8 @@ export interface CatalogPermissionExtensionPoint {
|
||||
CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>
|
||||
>
|
||||
): void;
|
||||
// (undocumented)
|
||||
addPermissions(...permissions: Array<Permission | Array<Permission>>): void;
|
||||
}
|
||||
|
||||
// @alpha (undocumented)
|
||||
|
||||
@@ -24,7 +24,10 @@ import {
|
||||
PlaceholderResolver,
|
||||
ScmLocationAnalyzer,
|
||||
} from '@backstage/plugin-catalog-node';
|
||||
import { PermissionRuleParams } from '@backstage/plugin-permission-common';
|
||||
import {
|
||||
Permission,
|
||||
PermissionRuleParams,
|
||||
} from '@backstage/plugin-permission-common';
|
||||
import { PermissionRule } from '@backstage/plugin-permission-node';
|
||||
|
||||
/**
|
||||
@@ -104,6 +107,7 @@ export type CatalogPermissionRuleInput<
|
||||
* @alpha
|
||||
*/
|
||||
export interface CatalogPermissionExtensionPoint {
|
||||
addPermissions(...permissions: Array<Permission | Array<Permission>>): void;
|
||||
addPermissionRules(
|
||||
...rules: Array<
|
||||
CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
BackstageCredentials,
|
||||
DiscoveryService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
|
||||
const responseSchema = z.object({
|
||||
items: z.array(
|
||||
@@ -90,9 +91,7 @@ export class PermissionIntegrationClient {
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Unexpected response from plugin upstream when applying conditions. Expected 200 but got ${response.status} - ${response.statusText}`,
|
||||
);
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
const result = responseSchema.parse(await response.json());
|
||||
|
||||
@@ -162,7 +162,6 @@ const applyConditions = <TResourceType extends string, TResource>(
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
* Takes some permission conditions and returns a definitive authorization result
|
||||
* on the resource to which they apply.
|
||||
*
|
||||
|
||||
@@ -5631,6 +5631,7 @@ __metadata:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/plugin-auth-node": "workspace:^"
|
||||
"@backstage/plugin-catalog-node": "workspace:^"
|
||||
"@backstage/plugin-catalog-unprocessed-entities-common": "workspace:^"
|
||||
"@backstage/plugin-permission-common": "workspace:^"
|
||||
"@backstage/plugin-permission-node": "workspace:^"
|
||||
|
||||
Reference in New Issue
Block a user