@backstage-community/plugin-rbac-backend 7.8.0 → 7.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @backstage-community/plugin-rbac-backend
2
2
 
3
+ ## 7.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - d737494: Backstage version bump to v1.48.5
8
+ - Updated dependencies [d737494]
9
+ - @backstage-community/plugin-rbac-common@1.24.1
10
+ - @backstage-community/plugin-rbac-node@1.18.1
11
+
12
+ ## 7.9.0
13
+
14
+ ### Minor Changes
15
+
16
+ - da170a1: Add support for group reference in superUsers list, using direct membership only
17
+
18
+ ### Patch Changes
19
+
20
+ - 8a6b81c: Updated dependency `@types/supertest` to `^7.0.0`.
21
+
3
22
  ## 7.8.0
4
23
 
5
24
  ### Minor Changes
package/README.md CHANGED
@@ -81,8 +81,11 @@ permission:
81
81
  superUsers:
82
82
  - name: user:default/alice
83
83
  - name: user:default/mike
84
+ - name: group:default/admins
84
85
  ```
85
86
 
87
+ > **Note:** **Transient memberships are not supported for `superUsers`.** Meaning, when a group is specified as a super user, only direct group memberships are taken into account. Users who belong to a sub-group of a configured super user group will not be granted super user access.
88
+
86
89
  For more information on the available API endpoints accessible to the policy administrators, refer to the [API documentation](./docs/apis.md).
87
90
 
88
91
  ### Configure plugins with permission
@@ -108,7 +108,9 @@ class RBACPermissionPolicy {
108
108
  });
109
109
  return { result: pluginPermissionCommon.AuthorizeResult.DENY };
110
110
  }
111
- if (this.superUserList.includes(userEntityRef)) {
111
+ if (this.superUserList.includes(userEntityRef) || user.info.ownershipEntityRefs.some(
112
+ (ref) => this.superUserList.includes(ref)
113
+ )) {
112
114
  await auditorEvent.success({
113
115
  meta: { result: pluginPermissionCommon.AuthorizeResult.ALLOW }
114
116
  });
@@ -1 +1 @@
1
- {"version":3,"file":"permission-policy.cjs.js","sources":["../../src/policies/permission-policy.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type {\n AuditorService,\n AuditorServiceEvent,\n AuthService,\n BackstageUserInfo,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport type { ConfigApi } from '@backstage/core-plugin-api';\nimport {\n AuthorizeResult,\n ConditionalPolicyDecision,\n isResourcePermission,\n PermissionCondition,\n PermissionCriteria,\n PermissionRuleParams,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport type {\n PermissionPolicy,\n PolicyQuery,\n PolicyQueryUser,\n} from '@backstage/plugin-permission-node';\n\nimport type { Knex } from 'knex';\n\nimport {\n NonEmptyArray,\n toPermissionAction,\n} from '@backstage-community/plugin-rbac-common';\n\nimport {\n setAdminPermissions,\n useAdminsFromConfig,\n} from '../admin-permissions/admin-creation';\nimport { createPermissionEvaluationAuditorEvent } from '../auditor/auditor';\nimport { replaceAliases } from '../conditional-aliases/alias-resolver';\nimport { ConditionalStorage } from '../database/conditional-storage';\nimport { RoleMetadataStorage } from '../database/role-metadata';\nimport { CSVFileWatcher } from '../file-permissions/csv-file-watcher';\nimport { YamlConditinalPoliciesFileWatcher } from '../file-permissions/yaml-conditional-file-watcher';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from '../service/plugin-endpoints';\n\nexport class RBACPermissionPolicy implements PermissionPolicy {\n private readonly superUserList?: string[];\n private readonly preferPermissionPolicy: boolean;\n\n public static async build(\n logger: LoggerService,\n auditor: AuditorService,\n configApi: ConfigApi,\n conditionalStorage: ConditionalStorage,\n enforcerDelegate: EnforcerDelegate,\n roleMetadataStorage: RoleMetadataStorage,\n knex: Knex,\n pluginMetadataCollector: PluginPermissionMetadataCollector,\n auth: AuthService,\n ): Promise<RBACPermissionPolicy> {\n const superUserList: string[] = [];\n const adminUsers = configApi.getOptionalConfigArray(\n 'permission.rbac.admin.users',\n );\n\n const superUsers = configApi.getOptionalConfigArray(\n 'permission.rbac.admin.superUsers',\n );\n\n const policiesFile = configApi.getOptionalString(\n 'permission.rbac.policies-csv-file',\n );\n\n const allowReload =\n configApi.getOptionalBoolean('permission.rbac.policyFileReload') || false;\n\n const conditionalPoliciesFile = configApi.getOptionalString(\n 'permission.rbac.conditionalPoliciesFile',\n );\n\n const preferPermissionPolicy =\n (configApi.getOptionalString(\n 'permission.rbac.policyDecisionPrecedence',\n ) ?? 'conditional') === 'basic';\n\n if (superUsers && superUsers.length > 0) {\n for (const user of superUsers) {\n const userName = user.getString('name');\n superUserList.push(userName);\n }\n }\n\n await useAdminsFromConfig(\n adminUsers || [],\n enforcerDelegate,\n auditor,\n roleMetadataStorage,\n knex,\n );\n await setAdminPermissions(enforcerDelegate, auditor);\n\n if (\n (!adminUsers || adminUsers.length === 0) &&\n (!superUsers || superUsers.length === 0)\n ) {\n logger.warn(\n 'There are no admins or super admins configured for the RBAC-backend plugin.',\n );\n }\n\n const csvFile = new CSVFileWatcher(\n policiesFile,\n allowReload,\n logger,\n enforcerDelegate,\n roleMetadataStorage,\n auditor,\n );\n await csvFile.initialize();\n\n const conditionalFile = new YamlConditinalPoliciesFileWatcher(\n conditionalPoliciesFile,\n allowReload,\n logger,\n conditionalStorage,\n auditor,\n auth,\n pluginMetadataCollector,\n roleMetadataStorage,\n enforcerDelegate,\n );\n await conditionalFile.initialize();\n\n if (!conditionalPoliciesFile) {\n // clean up conditional policies corresponding to roles from csv file\n logger.info('conditional policies file feature was disabled');\n await conditionalFile.cleanUpConditionalPolicies();\n }\n if (!policiesFile) {\n // remove roles and policies from csv file\n logger.info('csv policies file feature was disabled');\n await csvFile.cleanUpRolesAndPolicies();\n }\n\n return new RBACPermissionPolicy(\n enforcerDelegate,\n auditor,\n conditionalStorage,\n preferPermissionPolicy,\n superUserList,\n );\n }\n\n private constructor(\n private readonly enforcer: EnforcerDelegate,\n private readonly auditor: AuditorService,\n private readonly conditionStorage: ConditionalStorage,\n preferPermissionPolicy: boolean,\n superUserList?: string[],\n ) {\n this.superUserList = superUserList;\n this.preferPermissionPolicy = preferPermissionPolicy;\n }\n\n async handle(\n request: PolicyQuery,\n user?: PolicyQueryUser,\n ): Promise<PolicyDecision> {\n const userEntityRef = user?.info.userEntityRef ?? `user without entity`;\n\n const auditorEvent = await createPermissionEvaluationAuditorEvent(\n this.auditor,\n userEntityRef,\n request,\n );\n\n try {\n let status = false;\n const action = toPermissionAction(request.permission.attributes);\n\n if (!user) {\n await auditorEvent.success({\n meta: { result: AuthorizeResult.DENY },\n });\n return { result: AuthorizeResult.DENY };\n }\n\n if (this.superUserList!.includes(userEntityRef)) {\n await auditorEvent.success({\n meta: { result: AuthorizeResult.ALLOW },\n });\n return { result: AuthorizeResult.ALLOW };\n }\n\n const permissionName = request.permission.name;\n const roles = await this.enforcer.getRolesForUser(userEntityRef);\n // handle permission with 'resource' type\n const hasNamedPermission = await this.hasImplicitPermission(\n permissionName,\n action,\n roles,\n );\n\n // TODO: Temporary workaround to prevent breakages after the removal of the resource type `policy-entity` from the permission `policy.entity.create`\n if (\n request.permission.name === 'policy.entity.create' &&\n !hasNamedPermission\n ) {\n request.permission = {\n attributes: { action: 'create' },\n type: 'resource',\n resourceType: 'policy-entity',\n name: 'policy.entity.create',\n };\n }\n\n if (isResourcePermission(request.permission)) {\n const resourceType = request.permission.resourceType;\n // Let's set up higher priority for permission specified by name, than by resource type\n const obj = hasNamedPermission ? permissionName : resourceType;\n // handle conditions if they are present\n const conditionResult = await this.handleConditions(\n auditorEvent,\n userEntityRef,\n request,\n roles,\n user.info,\n );\n\n if (this.preferPermissionPolicy) {\n const hasResourcedPermission = await this.hasImplicitPermission(\n resourceType,\n action,\n roles,\n );\n // Permission policy first\n if (hasNamedPermission || hasResourcedPermission) {\n status = await this.isAuthorized(userEntityRef, obj, action, roles);\n } else if (conditionResult) {\n return conditionResult;\n }\n } else {\n if (conditionResult) return conditionResult;\n status = await this.isAuthorized(userEntityRef, obj, action, roles);\n }\n } else {\n // handle permission with 'basic' type\n status = await this.isAuthorized(\n userEntityRef,\n permissionName,\n action,\n roles,\n );\n }\n\n const result = status ? AuthorizeResult.ALLOW : AuthorizeResult.DENY;\n\n await auditorEvent.success({ meta: { result } });\n return { result };\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: { result: AuthorizeResult.DENY },\n });\n return { result: AuthorizeResult.DENY };\n }\n }\n\n private async hasImplicitPermission(\n permissionName: string,\n action: string,\n roles: string[],\n ): Promise<boolean> {\n for (const role of roles) {\n const perms = await this.enforcer.getFilteredPolicy(\n 0,\n role,\n permissionName,\n action,\n );\n if (perms.length > 0) {\n return true;\n }\n }\n\n return false;\n }\n\n private isAuthorized = async (\n userIdentity: string,\n permission: string,\n action: string,\n roles: string[],\n ): Promise<boolean> => {\n return await this.enforcer.enforce(userIdentity, permission, action, roles);\n };\n\n private async handleConditions(\n auditorEvent: AuditorServiceEvent,\n userEntityRef: string,\n request: PolicyQuery,\n roles: string[],\n userInfo: BackstageUserInfo,\n ): Promise<PolicyDecision | undefined> {\n const permissionName = request.permission.name;\n const resourceType = (request.permission as ResourcePermission)\n .resourceType;\n const action = toPermissionAction(request.permission.attributes);\n\n const conditions: PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >[] = [];\n let pluginId = '';\n for (const role of roles) {\n const conditionalDecisions = await this.conditionStorage.filterConditions(\n role,\n undefined,\n resourceType,\n [action],\n [permissionName],\n );\n\n if (conditionalDecisions.length === 1) {\n pluginId = conditionalDecisions[0].pluginId;\n conditions.push(conditionalDecisions[0].conditions);\n }\n\n // this error is unexpected and should not happen, but just in case handle it.\n if (conditionalDecisions.length > 1) {\n await auditorEvent.fail({\n error: new Error(\n `Detected ${JSON.stringify(\n conditionalDecisions,\n )} collisions for conditional policies. Expected to find a stored single condition for permission with name ${permissionName}, resource type ${resourceType}, action ${action} for user ${userEntityRef}`,\n ),\n meta: { result: AuthorizeResult.DENY },\n });\n return {\n result: AuthorizeResult.DENY,\n };\n }\n }\n\n if (conditions.length > 0) {\n const result: ConditionalPolicyDecision = {\n pluginId,\n result: AuthorizeResult.CONDITIONAL,\n resourceType,\n conditions: {\n anyOf: conditions as NonEmptyArray<\n PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >\n >,\n },\n };\n\n replaceAliases(result.conditions, userInfo);\n\n await auditorEvent.success({ meta: { ...result } });\n return result;\n }\n return undefined;\n }\n}\n"],"names":["useAdminsFromConfig","setAdminPermissions","CSVFileWatcher","YamlConditinalPoliciesFileWatcher","createPermissionEvaluationAuditorEvent","toPermissionAction","AuthorizeResult","isResourcePermission","replaceAliases"],"mappings":"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"}
1
+ {"version":3,"file":"permission-policy.cjs.js","sources":["../../src/policies/permission-policy.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type {\n AuditorService,\n AuditorServiceEvent,\n AuthService,\n BackstageUserInfo,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport type { ConfigApi } from '@backstage/core-plugin-api';\nimport {\n AuthorizeResult,\n ConditionalPolicyDecision,\n isResourcePermission,\n PermissionCondition,\n PermissionCriteria,\n PermissionRuleParams,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport type {\n PermissionPolicy,\n PolicyQuery,\n PolicyQueryUser,\n} from '@backstage/plugin-permission-node';\n\nimport type { Knex } from 'knex';\n\nimport {\n NonEmptyArray,\n toPermissionAction,\n} from '@backstage-community/plugin-rbac-common';\n\nimport {\n setAdminPermissions,\n useAdminsFromConfig,\n} from '../admin-permissions/admin-creation';\nimport { createPermissionEvaluationAuditorEvent } from '../auditor/auditor';\nimport { replaceAliases } from '../conditional-aliases/alias-resolver';\nimport { ConditionalStorage } from '../database/conditional-storage';\nimport { RoleMetadataStorage } from '../database/role-metadata';\nimport { CSVFileWatcher } from '../file-permissions/csv-file-watcher';\nimport { YamlConditinalPoliciesFileWatcher } from '../file-permissions/yaml-conditional-file-watcher';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from '../service/plugin-endpoints';\n\nexport class RBACPermissionPolicy implements PermissionPolicy {\n private readonly superUserList?: string[];\n private readonly preferPermissionPolicy: boolean;\n\n public static async build(\n logger: LoggerService,\n auditor: AuditorService,\n configApi: ConfigApi,\n conditionalStorage: ConditionalStorage,\n enforcerDelegate: EnforcerDelegate,\n roleMetadataStorage: RoleMetadataStorage,\n knex: Knex,\n pluginMetadataCollector: PluginPermissionMetadataCollector,\n auth: AuthService,\n ): Promise<RBACPermissionPolicy> {\n const superUserList: string[] = [];\n const adminUsers = configApi.getOptionalConfigArray(\n 'permission.rbac.admin.users',\n );\n\n const superUsers = configApi.getOptionalConfigArray(\n 'permission.rbac.admin.superUsers',\n );\n\n const policiesFile = configApi.getOptionalString(\n 'permission.rbac.policies-csv-file',\n );\n\n const allowReload =\n configApi.getOptionalBoolean('permission.rbac.policyFileReload') || false;\n\n const conditionalPoliciesFile = configApi.getOptionalString(\n 'permission.rbac.conditionalPoliciesFile',\n );\n\n const preferPermissionPolicy =\n (configApi.getOptionalString(\n 'permission.rbac.policyDecisionPrecedence',\n ) ?? 'conditional') === 'basic';\n\n if (superUsers && superUsers.length > 0) {\n for (const user of superUsers) {\n const userName = user.getString('name');\n superUserList.push(userName);\n }\n }\n\n await useAdminsFromConfig(\n adminUsers || [],\n enforcerDelegate,\n auditor,\n roleMetadataStorage,\n knex,\n );\n await setAdminPermissions(enforcerDelegate, auditor);\n\n if (\n (!adminUsers || adminUsers.length === 0) &&\n (!superUsers || superUsers.length === 0)\n ) {\n logger.warn(\n 'There are no admins or super admins configured for the RBAC-backend plugin.',\n );\n }\n\n const csvFile = new CSVFileWatcher(\n policiesFile,\n allowReload,\n logger,\n enforcerDelegate,\n roleMetadataStorage,\n auditor,\n );\n await csvFile.initialize();\n\n const conditionalFile = new YamlConditinalPoliciesFileWatcher(\n conditionalPoliciesFile,\n allowReload,\n logger,\n conditionalStorage,\n auditor,\n auth,\n pluginMetadataCollector,\n roleMetadataStorage,\n enforcerDelegate,\n );\n await conditionalFile.initialize();\n\n if (!conditionalPoliciesFile) {\n // clean up conditional policies corresponding to roles from csv file\n logger.info('conditional policies file feature was disabled');\n await conditionalFile.cleanUpConditionalPolicies();\n }\n if (!policiesFile) {\n // remove roles and policies from csv file\n logger.info('csv policies file feature was disabled');\n await csvFile.cleanUpRolesAndPolicies();\n }\n\n return new RBACPermissionPolicy(\n enforcerDelegate,\n auditor,\n conditionalStorage,\n preferPermissionPolicy,\n superUserList,\n );\n }\n\n private constructor(\n private readonly enforcer: EnforcerDelegate,\n private readonly auditor: AuditorService,\n private readonly conditionStorage: ConditionalStorage,\n preferPermissionPolicy: boolean,\n superUserList?: string[],\n ) {\n this.superUserList = superUserList;\n this.preferPermissionPolicy = preferPermissionPolicy;\n }\n\n async handle(\n request: PolicyQuery,\n user?: PolicyQueryUser,\n ): Promise<PolicyDecision> {\n const userEntityRef = user?.info.userEntityRef ?? `user without entity`;\n\n const auditorEvent = await createPermissionEvaluationAuditorEvent(\n this.auditor,\n userEntityRef,\n request,\n );\n\n try {\n let status = false;\n const action = toPermissionAction(request.permission.attributes);\n\n if (!user) {\n await auditorEvent.success({\n meta: { result: AuthorizeResult.DENY },\n });\n return { result: AuthorizeResult.DENY };\n }\n\n if (\n this.superUserList!.includes(userEntityRef) ||\n user.info.ownershipEntityRefs.some(ref =>\n this.superUserList!.includes(ref),\n )\n ) {\n await auditorEvent.success({\n meta: { result: AuthorizeResult.ALLOW },\n });\n return { result: AuthorizeResult.ALLOW };\n }\n\n const permissionName = request.permission.name;\n const roles = await this.enforcer.getRolesForUser(userEntityRef);\n // handle permission with 'resource' type\n const hasNamedPermission = await this.hasImplicitPermission(\n permissionName,\n action,\n roles,\n );\n\n // TODO: Temporary workaround to prevent breakages after the removal of the resource type `policy-entity` from the permission `policy.entity.create`\n if (\n request.permission.name === 'policy.entity.create' &&\n !hasNamedPermission\n ) {\n request.permission = {\n attributes: { action: 'create' },\n type: 'resource',\n resourceType: 'policy-entity',\n name: 'policy.entity.create',\n };\n }\n\n if (isResourcePermission(request.permission)) {\n const resourceType = request.permission.resourceType;\n // Let's set up higher priority for permission specified by name, than by resource type\n const obj = hasNamedPermission ? permissionName : resourceType;\n // handle conditions if they are present\n const conditionResult = await this.handleConditions(\n auditorEvent,\n userEntityRef,\n request,\n roles,\n user.info,\n );\n\n if (this.preferPermissionPolicy) {\n const hasResourcedPermission = await this.hasImplicitPermission(\n resourceType,\n action,\n roles,\n );\n // Permission policy first\n if (hasNamedPermission || hasResourcedPermission) {\n status = await this.isAuthorized(userEntityRef, obj, action, roles);\n } else if (conditionResult) {\n return conditionResult;\n }\n } else {\n if (conditionResult) return conditionResult;\n status = await this.isAuthorized(userEntityRef, obj, action, roles);\n }\n } else {\n // handle permission with 'basic' type\n status = await this.isAuthorized(\n userEntityRef,\n permissionName,\n action,\n roles,\n );\n }\n\n const result = status ? AuthorizeResult.ALLOW : AuthorizeResult.DENY;\n\n await auditorEvent.success({ meta: { result } });\n return { result };\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: { result: AuthorizeResult.DENY },\n });\n return { result: AuthorizeResult.DENY };\n }\n }\n\n private async hasImplicitPermission(\n permissionName: string,\n action: string,\n roles: string[],\n ): Promise<boolean> {\n for (const role of roles) {\n const perms = await this.enforcer.getFilteredPolicy(\n 0,\n role,\n permissionName,\n action,\n );\n if (perms.length > 0) {\n return true;\n }\n }\n\n return false;\n }\n\n private isAuthorized = async (\n userIdentity: string,\n permission: string,\n action: string,\n roles: string[],\n ): Promise<boolean> => {\n return await this.enforcer.enforce(userIdentity, permission, action, roles);\n };\n\n private async handleConditions(\n auditorEvent: AuditorServiceEvent,\n userEntityRef: string,\n request: PolicyQuery,\n roles: string[],\n userInfo: BackstageUserInfo,\n ): Promise<PolicyDecision | undefined> {\n const permissionName = request.permission.name;\n const resourceType = (request.permission as ResourcePermission)\n .resourceType;\n const action = toPermissionAction(request.permission.attributes);\n\n const conditions: PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >[] = [];\n let pluginId = '';\n for (const role of roles) {\n const conditionalDecisions = await this.conditionStorage.filterConditions(\n role,\n undefined,\n resourceType,\n [action],\n [permissionName],\n );\n\n if (conditionalDecisions.length === 1) {\n pluginId = conditionalDecisions[0].pluginId;\n conditions.push(conditionalDecisions[0].conditions);\n }\n\n // this error is unexpected and should not happen, but just in case handle it.\n if (conditionalDecisions.length > 1) {\n await auditorEvent.fail({\n error: new Error(\n `Detected ${JSON.stringify(\n conditionalDecisions,\n )} collisions for conditional policies. Expected to find a stored single condition for permission with name ${permissionName}, resource type ${resourceType}, action ${action} for user ${userEntityRef}`,\n ),\n meta: { result: AuthorizeResult.DENY },\n });\n return {\n result: AuthorizeResult.DENY,\n };\n }\n }\n\n if (conditions.length > 0) {\n const result: ConditionalPolicyDecision = {\n pluginId,\n result: AuthorizeResult.CONDITIONAL,\n resourceType,\n conditions: {\n anyOf: conditions as NonEmptyArray<\n PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >\n >,\n },\n };\n\n replaceAliases(result.conditions, userInfo);\n\n await auditorEvent.success({ meta: { ...result } });\n return result;\n }\n return undefined;\n }\n}\n"],"names":["useAdminsFromConfig","setAdminPermissions","CSVFileWatcher","YamlConditinalPoliciesFileWatcher","createPermissionEvaluationAuditorEvent","toPermissionAction","AuthorizeResult","isResourcePermission","replaceAliases"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage-community/plugin-rbac-backend",
3
- "version": "7.8.0",
3
+ "version": "7.9.1",
4
4
  "main": "dist/index.cjs.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -36,8 +36,8 @@
36
36
  "postpack": "backstage-cli package postpack"
37
37
  },
38
38
  "dependencies": {
39
- "@backstage-community/plugin-rbac-common": "^1.24.0",
40
- "@backstage-community/plugin-rbac-node": "^1.18.0",
39
+ "@backstage-community/plugin-rbac-common": "^1.24.1",
40
+ "@backstage-community/plugin-rbac-node": "^1.18.1",
41
41
  "@backstage/backend-defaults": "^0.15.2",
42
42
  "@backstage/backend-plugin-api": "^1.7.0",
43
43
  "@backstage/catalog-client": "^1.13.0",
@@ -72,7 +72,7 @@
72
72
  "@types/knex": "^0.16.1",
73
73
  "@types/lodash": "^4.14.151",
74
74
  "@types/node": "22.19.11",
75
- "@types/supertest": "6.0.3",
75
+ "@types/supertest": "7.2.0",
76
76
  "knex-mock-client": "3.0.2",
77
77
  "msw": "1.3.5",
78
78
  "qs": "6.14.1",