diff --git a/packages/backend-defaults/src/entrypoints/permissionIntegrations/permissionIntegrationsServiceFactory.ts b/packages/backend-defaults/src/entrypoints/permissionIntegrations/permissionIntegrationsServiceFactory.ts index 3b668514ce..b083439515 100644 --- a/packages/backend-defaults/src/entrypoints/permissionIntegrations/permissionIntegrationsServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/permissionIntegrations/permissionIntegrationsServiceFactory.ts @@ -62,6 +62,14 @@ export const permissionIntegrationsServiceFactory = createServiceFactory({ } router.addPermissions(permissions); }, + addPermissionRules(rules) { + if (started) { + throw new Error( + 'Cannot add permission rules after the plugin has started', + ); + } + router.addPermissionRules(rules); + }, }; }, }); diff --git a/packages/backend-plugin-api/report.api.md b/packages/backend-plugin-api/report.api.md index 2a8300ccec..224a057686 100644 --- a/packages/backend-plugin-api/report.api.md +++ b/packages/backend-plugin-api/report.api.md @@ -434,6 +434,7 @@ export interface LoggerService { // @public export interface PermissionIntegrationsService { + addPermissionRules(rules: PermissionRule[]): void; addPermissions(permissions: Permission[]): void; addResourceType( options: PermissionIntegrationsServiceAddResourceTypeOptions< diff --git a/packages/backend-plugin-api/src/services/definitions/PermissionIntegrationsService.ts b/packages/backend-plugin-api/src/services/definitions/PermissionIntegrationsService.ts index fd25a16b1c..2d4a2e0ffb 100644 --- a/packages/backend-plugin-api/src/services/definitions/PermissionIntegrationsService.ts +++ b/packages/backend-plugin-api/src/services/definitions/PermissionIntegrationsService.ts @@ -77,6 +77,21 @@ export interface PermissionIntegrationsService { */ addPermissions(permissions: Permission[]): void; + /** + * Adds a set of permission rules to the permission system for a resource type + * that is owned by this plugin. + * + * @remarks + * + * Rules should be created using corresponding `create*PermissionRule` + * functions exported by plugins, who in turn are created with + * `makeCreatePermissionRule`. + * + * Rules can be added either directly by the plugin itself or through a plugin + * module. + */ + addPermissionRules(rules: PermissionRule[]): void; + /** * Add a new resource type that is owned by this plugin to the permission * system. diff --git a/plugins/permission-node/report.api.md b/plugins/permission-node/report.api.md index 748ed58f3b..a55cbbf9c5 100644 --- a/plugins/permission-node/report.api.md +++ b/plugins/permission-node/report.api.md @@ -142,6 +142,7 @@ export function createPermissionIntegrationRouter< >, ): express.Router & { addPermissions(permissions: Permission[]): void; + addPermissionRules(rules: PermissionRule[]): void; addResourceType( resource: CreatePermissionIntegrationRouterResourceOptions< TResourceType, diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index 0bce007c89..dbb5647157 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -1006,14 +1006,19 @@ describe('createPermissionIntegrationRouter', () => { resourceType: 'test-resource', permissions: [testPermission], getResources: defaultMockedGetResources1, - rules: [testRule1, testRule2], + rules: [testRule1], }); + router.addPermissionRules([testRule2]); + + // This one is for the resource added below, it should be possible to add rules before the resource typeof + router.addPermissionRules([testRule3]); + router.addResourceType({ resourceType: 'test-resource-2', permissions: [testPermission2], getResources: defaultMockedGetResources2, - rules: [testRule3], + rules: [], }); const responseAfter = await request(express().use(router)).get( diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 9ef5b564d8..f24f4827e7 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -308,6 +308,28 @@ class PermissionIntegrationMetadataStore { } } + addPermissionRules(rules: PermissionRule[]) { + for (const rule of rules) { + const rulesByName = + this.#rulesByTypeByName.get(rule.resourceType) ?? new Map(); + this.#rulesByTypeByName.set(rule.resourceType, rulesByName); + + if (rulesByName.has(rule.name)) { + throw new Error( + `Refused to add permission rule for type '${rule.resourceType}' with name '${rule.name}' because it already exists`, + ); + } + rulesByName.set(rule.name, rule); + + this.#serializedRules.push({ + name: rule.name, + description: rule.description, + resourceType: rule.resourceType, + paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})), + }); + } + } + addResourceType( resource: CreatePermissionIntegrationRouterResourceOptions, ) { @@ -320,24 +342,8 @@ class PermissionIntegrationMetadataStore { } this.#resourcesByType.set(resourceType, resource); - for (const rule of resource.rules) { - const rulesByName = - this.#rulesByTypeByName.get(resourceType) ?? new Map(); - this.#rulesByTypeByName.set(resourceType, rulesByName); - - if (rulesByName.has(rule.name)) { - throw new Error( - `Refused to add permission rule for type '${resourceType}' with name '${rule.name}' because it already exists`, - ); - } - rulesByName.set(rule.name, rule); - - this.#serializedRules.push({ - name: rule.name, - description: rule.description, - resourceType: rule.resourceType, - paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})), - }); + if (resource.rules) { + this.addPermissionRules(resource.rules); } if (resource.permissions) { @@ -411,6 +417,7 @@ export function createPermissionIntegrationRouter< >, ): express.Router & { addPermissions(permissions: Permission[]): void; + addPermissionRules(rules: PermissionRule[]): void; addResourceType( resource: CreatePermissionIntegrationRouterResourceOptions< TResourceType, @@ -495,6 +502,9 @@ export function createPermissionIntegrationRouter< addPermissions(permissions: Permission[]) { store.addPermissions(permissions); }, + addPermissionRules(rules: PermissionRule[]) { + store.addPermissionRules(rules); + }, addResourceType( resource: CreatePermissionIntegrationRouterResourceOptions< TResourceType,