Merge pull request #28790 from backstage/catalog-permissions-batch-entities

catalog: use entitiesBatch when applying conditional conditions
This commit is contained in:
Vincenzo Scamporlino
2025-02-13 19:11:54 +01:00
committed by GitHub
2 changed files with 23 additions and 46 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Improved performance when applying conditional decisions to entities within the permission framework.
@@ -26,9 +26,7 @@ import {
FieldFormatEntityPolicy,
makeValidator,
NoForeignRootFieldsEntityPolicy,
parseEntityRef,
SchemaValidEntityPolicy,
stringifyEntityRef,
Validators,
} from '@backstage/catalog-model';
import { ScmIntegrations } from '@backstage/integration';
@@ -116,7 +114,6 @@ import { createRouter } from './createRouter';
import { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';
import { DefaultLocationService } from './DefaultLocationService';
import { DefaultRefreshService } from './DefaultRefreshService';
import { basicEntityFilter } from './request';
import { entitiesResponseToObjects } from './response';
import { catalogEntityPermissionResourceRef } from '@backstage/plugin-catalog-node/alpha';
@@ -381,7 +378,7 @@ export class CatalogBuilder {
return [
new FileReaderProcessor(),
new UrlReaderProcessor({ reader, logger, config }),
new UrlReaderProcessor({ reader, logger }),
CodeOwnersProcessor.fromConfig(config, { logger, reader }),
new AnnotateLocationEntityProcessor({ integrations }),
];
@@ -559,60 +556,35 @@ export class CatalogBuilder {
const entitiesCatalog = new AuthorizedEntitiesCatalog(
unauthorizedEntitiesCatalog,
permissionsService,
permissionsRegistry
? createConditionTransformer(
permissionsRegistry.getPermissionRuleset(
catalogEntityPermissionResourceRef,
),
)
: createConditionTransformer(this.permissionRules),
createConditionTransformer(this.permissionRules),
);
const catalogPermissionResource = {
resourceType: RESOURCE_TYPE_CATALOG_ENTITY,
getResources: async (resourceRefs: string[]) => {
const { entities } = await unauthorizedEntitiesCatalog.entities({
credentials: await auth.getOwnServiceCredentials(),
filter: {
anyOf: resourceRefs.map(resourceRef => {
const { kind, namespace, name } = parseEntityRef(resourceRef);
const getResources = async (resourceRefs: string[]) => {
const { items } = await unauthorizedEntitiesCatalog.entitiesBatch({
credentials: await auth.getOwnServiceCredentials(),
entityRefs: resourceRefs,
});
return basicEntityFilter({
kind,
'metadata.namespace': namespace,
'metadata.name': name,
});
}),
},
});
const entitiesByRef = Object.fromEntries(
entitiesResponseToObjects(entities)
.filter((x): x is Entity => Boolean(x))
.map(entity => [stringifyEntityRef(entity), entity]),
);
return resourceRefs.map(
resourceRef =>
entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],
);
},
permissions: this.permissions,
rules: this.permissionRules,
} as const;
return entitiesResponseToObjects(items).map(e => e || undefined);
};
let permissionIntegrationRouter:
| ReturnType<typeof createPermissionIntegrationRouter>
| undefined;
if (permissionsRegistry) {
permissionsRegistry.addResourceType({
...catalogPermissionResource,
resourceRef: catalogEntityPermissionResourceRef,
getResources,
permissions: this.permissions,
rules: this.permissionRules,
});
} else {
permissionIntegrationRouter = createPermissionIntegrationRouter(
catalogPermissionResource,
);
permissionIntegrationRouter = createPermissionIntegrationRouter({
resourceType: RESOURCE_TYPE_CATALOG_ENTITY,
getResources,
permissions: this.permissions,
rules: this.permissionRules,
});
}
const locationStore = new DefaultLocationStore(dbClient);