From 2d43438e45e9f1bf6277165ead0c66f00aa5dc90 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Wed, 27 Nov 2024 17:02:09 +0100 Subject: [PATCH 1/4] feat: maintenance root roles --- .../features/maintenance/maintenance-controller.ts | 11 ++++++++--- src/lib/types/permissions.ts | 7 +++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/lib/features/maintenance/maintenance-controller.ts b/src/lib/features/maintenance/maintenance-controller.ts index bba95b8d5921..f7db299245a9 100644 --- a/src/lib/features/maintenance/maintenance-controller.ts +++ b/src/lib/features/maintenance/maintenance-controller.ts @@ -1,4 +1,9 @@ -import { ADMIN, type IUnleashConfig, type IUnleashServices } from '../../types'; +import { + NONE, + UPDATE_MAINTENANCE_MODE, + type IUnleashConfig, + type IUnleashServices, +} from '../../types'; import type { Request, Response } from 'express'; import Controller from '../../routes/controller'; import type { Logger } from '../../logger'; @@ -38,7 +43,7 @@ export default class MaintenanceController extends Controller { this.route({ method: 'post', path: '', - permission: ADMIN, + permission: UPDATE_MAINTENANCE_MODE, handler: this.toggleMaintenance, middleware: [ this.openApiService.validPath({ @@ -58,7 +63,7 @@ export default class MaintenanceController extends Controller { this.route({ method: 'get', path: '', - permission: ADMIN, + permission: NONE, handler: this.getMaintenance, middleware: [ this.openApiService.validPath({ diff --git a/src/lib/types/permissions.ts b/src/lib/types/permissions.ts index 245526ca2b3e..06f89baec1d9 100644 --- a/src/lib/types/permissions.ts +++ b/src/lib/types/permissions.ts @@ -41,6 +41,9 @@ export const CREATE_TAG_TYPE = 'CREATE_TAG_TYPE'; export const UPDATE_TAG_TYPE = 'UPDATE_TAG_TYPE'; export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE'; +export const UPDATE_MAINTENANCE_MODE = 'UPDATE_MAINTENANCE_MODE'; +export const UPDATE_INSTANCE_BANNERS = 'UPDATE_INSTANCE_BANNERS'; + // Project export const CREATE_FEATURE = 'CREATE_FEATURE'; export const UPDATE_FEATURE = 'UPDATE_FEATURE'; @@ -141,4 +144,8 @@ export const ROOT_PERMISSION_CATEGORIES = [ RELEASE_PLAN_TEMPLATE_UPDATE, ], }, + { + label: 'Instance maintenance', + permissions: [UPDATE_MAINTENANCE_MODE, UPDATE_INSTANCE_BANNERS], + }, ]; From 7a05ec6ba5f9878154eb4f6563069bf983344179 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:04:14 +0100 Subject: [PATCH 2/4] feat(cjux-278): gradual permissions for maintenance --- frontend/src/component/admin/banners/Banners.tsx | 3 ++- frontend/src/component/admin/maintenance/index.tsx | 3 ++- .../RolePermissionCategories.tsx | 10 +++++++++- .../hooks/api/getters/useAuth/useAuthPermissions.ts | 5 +++-- frontend/src/interfaces/uiConfig.ts | 1 + src/lib/types/experimental.ts | 7 ++++++- src/lib/types/permissions.ts | 11 ++++++++++- src/server-dev.ts | 1 + 8 files changed, 34 insertions(+), 7 deletions(-) diff --git a/frontend/src/component/admin/banners/Banners.tsx b/frontend/src/component/admin/banners/Banners.tsx index 9e4a2070a8df..db86315e1495 100644 --- a/frontend/src/component/admin/banners/Banners.tsx +++ b/frontend/src/component/admin/banners/Banners.tsx @@ -3,6 +3,7 @@ import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuar import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature'; import { BannersTable } from './BannersTable/BannersTable'; +import { UPDATE_INSTANCE_BANNERS } from '@server/types/permissions'; export const Banners = () => { const { isEnterprise } = useUiConfig(); @@ -13,7 +14,7 @@ export const Banners = () => { return (
- +
diff --git a/frontend/src/component/admin/maintenance/index.tsx b/frontend/src/component/admin/maintenance/index.tsx index 505dd10e4963..9774adbc312e 100644 --- a/frontend/src/component/admin/maintenance/index.tsx +++ b/frontend/src/component/admin/maintenance/index.tsx @@ -6,10 +6,11 @@ import { Box, styled } from '@mui/material'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { MaintenanceTooltip } from './MaintenanceTooltip'; import { MaintenanceToggle } from './MaintenanceToggle'; +import { UPDATE_MAINTENANCE_MODE } from '@server/types/permissions'; export const MaintenanceAdmin = () => (
- +
diff --git a/frontend/src/component/admin/roles/RoleForm/RolePermissionCategories/RolePermissionCategories.tsx b/frontend/src/component/admin/roles/RoleForm/RolePermissionCategories/RolePermissionCategories.tsx index 0fbe05ea7967..d8097bc22a25 100644 --- a/frontend/src/component/admin/roles/RoleForm/RolePermissionCategories/RolePermissionCategories.tsx +++ b/frontend/src/component/admin/roles/RoleForm/RolePermissionCategories/RolePermissionCategories.tsx @@ -42,6 +42,9 @@ export const RolePermissionCategories = ({ }); const releasePlansEnabled = useUiFlag('releasePlans'); + const granularAdminPermissionsEnabled = useUiFlag( + 'granularAdminPermissions', + ); const isProjectRole = PROJECT_ROLE_TYPES.includes(type); @@ -85,10 +88,15 @@ export const RolePermissionCategories = ({ releasePlansEnabled || label !== 'Release plan templates', ) + .filter( + ({ label }) => + granularAdminPermissionsEnabled || + label !== 'Instance maintenance', + ) .map(({ label, type, permissions }) => ( permission.permission === 'ADMIN', + permissions = permissions.filter((permission) => + MAINTENANCE_MODE_PERMISSIONS.includes(permission.permission), ); } return permissions; diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index 19263be2b3e2..b135df6b0219 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -94,6 +94,7 @@ export type UiFlags = { showUserDeviceCount?: boolean; flagOverviewRedesign?: boolean; licensedUsers?: boolean; + granularAdminPermissions?: boolean; }; export interface IVersionInfo { diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 4bea097ec534..39f5e0bf73a4 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -61,7 +61,8 @@ export type IFlagKey = | 'memorizeStats' | 'licensedUsers' | 'streaming' - | 'etagVariant'; + | 'etagVariant' + | 'granularAdminPermissions'; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; @@ -290,6 +291,10 @@ const flags: IFlags = { feature_enabled: false, enabled: false, }, + granularAdminPermissions: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_GRANULAR_ADMIN_PERMISSIONS, + false, + ), }; export const defaultExperimentalOptions: IExperimentalOptions = { diff --git a/src/lib/types/permissions.ts b/src/lib/types/permissions.ts index 06f89baec1d9..2ce1d977a011 100644 --- a/src/lib/types/permissions.ts +++ b/src/lib/types/permissions.ts @@ -86,7 +86,7 @@ export const RELEASE_PLAN_TEMPLATE_DELETE = 'RELEASE_PLAN_TEMPLATE_DELETE'; export const ROOT_PERMISSION_CATEGORIES = [ { - label: 'Addon', + label: 'Integration', permissions: [CREATE_ADDON, UPDATE_ADDON, DELETE_ADDON], }, { @@ -149,3 +149,12 @@ export const ROOT_PERMISSION_CATEGORIES = [ permissions: [UPDATE_MAINTENANCE_MODE, UPDATE_INSTANCE_BANNERS], }, ]; + +// Used on Frontend, to allow admin panel use for users with custom root roles +export const MAINTENANCE_MODE_PERMISSIONS = [ + ADMIN, + READ_ROLE, + READ_CLIENT_API_TOKEN, + READ_FRONTEND_API_TOKEN, + UPDATE_MAINTENANCE_MODE, +]; diff --git a/src/server-dev.ts b/src/server-dev.ts index 1b0d7b0eb7e5..d4b7e36deb20 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -57,6 +57,7 @@ process.nextTick(async () => { showUserDeviceCount: true, flagOverviewRedesign: false, licensedUsers: true, + granularAdminPermissions: true, }, }, authentication: { From a7716f1f40d3b3a6dd08fed8fa4c64b70d9a96ec Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:09:54 +0100 Subject: [PATCH 3/4] update maintenance permissions --- src/lib/features/maintenance/maintenance-controller.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/features/maintenance/maintenance-controller.ts b/src/lib/features/maintenance/maintenance-controller.ts index f7db299245a9..71df5702ed0c 100644 --- a/src/lib/features/maintenance/maintenance-controller.ts +++ b/src/lib/features/maintenance/maintenance-controller.ts @@ -1,5 +1,5 @@ import { - NONE, + ADMIN, UPDATE_MAINTENANCE_MODE, type IUnleashConfig, type IUnleashServices, @@ -43,7 +43,7 @@ export default class MaintenanceController extends Controller { this.route({ method: 'post', path: '', - permission: UPDATE_MAINTENANCE_MODE, + permission: [ADMIN, UPDATE_MAINTENANCE_MODE], handler: this.toggleMaintenance, middleware: [ this.openApiService.validPath({ @@ -63,7 +63,7 @@ export default class MaintenanceController extends Controller { this.route({ method: 'get', path: '', - permission: NONE, + permission: [ADMIN, UPDATE_MAINTENANCE_MODE], handler: this.getMaintenance, middleware: [ this.openApiService.validPath({ From ca25fb3aa4db632df0c2209816f654a70e9bba99 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:34:31 +0100 Subject: [PATCH 4/4] fix: typo --- src/lib/types/experimental.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 39f5e0bf73a4..72cd6cffacb4 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -60,9 +60,9 @@ export type IFlagKey = | 'deleteStaleUserSessions' | 'memorizeStats' | 'licensedUsers' + | 'granularAdminPermissions' | 'streaming' - | 'etagVariant' - | 'granularAdminPermissions'; + | 'etagVariant'; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; @@ -282,6 +282,10 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_FLAG_LICENSED_USERS, false, ), + granularAdminPermissions: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_GRANULAR_ADMIN_PERMISSIONS, + false, + ), streaming: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_STREAMING, false, @@ -291,10 +295,6 @@ const flags: IFlags = { feature_enabled: false, enabled: false, }, - granularAdminPermissions: parseEnvVarBoolean( - process.env.UNLEASH_EXPERIMENTAL_GRANULAR_ADMIN_PERMISSIONS, - false, - ), }; export const defaultExperimentalOptions: IExperimentalOptions = {