Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cjux-278): maintenance root roles #8875

Merged
merged 4 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion frontend/src/component/admin/banners/Banners.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -13,7 +14,7 @@ export const Banners = () => {

return (
<div>
<PermissionGuard permissions={ADMIN}>
<PermissionGuard permissions={[ADMIN, UPDATE_INSTANCE_BANNERS]}>
<BannersTable />
</PermissionGuard>
</div>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/component/admin/maintenance/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know we could import stuff from the server? Should it go in AccessProvider/permissions to be consistent with how we're doing it today? I think only defining it in one place is cool, though, but why is it not something we're already doing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for noticing this. It needs refactoring. I'll post another PR, because it turns out there are inconsistencies all over this.


export const MaintenanceAdmin = () => (
<div>
<PermissionGuard permissions={ADMIN}>
<PermissionGuard permissions={[ADMIN, UPDATE_MAINTENANCE_MODE]}>
<MaintenancePage />
</PermissionGuard>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export const RolePermissionCategories = ({
});

const releasePlansEnabled = useUiFlag('releasePlans');
const granularAdminPermissionsEnabled = useUiFlag(
'granularAdminPermissions',
);

const isProjectRole = PROJECT_ROLE_TYPES.includes(type);

Expand Down Expand Up @@ -85,10 +88,15 @@ export const RolePermissionCategories = ({
releasePlansEnabled ||
label !== 'Release plan templates',
)
.filter(
({ label }) =>
granularAdminPermissionsEnabled ||
label !== 'Instance maintenance',
)
.map(({ label, type, permissions }) => (
<RolePermissionCategory
key={label}
title={`${label} permissions`}
title={label}
context={label.toLowerCase()}
Icon={
type === PROJECT_PERMISSION_TYPE ? (
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/hooks/api/getters/useAuth/useAuthPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from './useAuthEndpoint';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import type { IUiConfig } from 'interfaces/uiConfig';
import { MAINTENANCE_MODE_PERMISSIONS } from '@server/types/permissions';

interface IUseAuthPermissionsOutput {
permissions?: IPermission[];
Expand All @@ -22,8 +23,8 @@ const getPermissions = (
? auth.data.permissions
: undefined;
if (permissions && uiConfig?.maintenanceMode) {
permissions = permissions.filter(
(permission) => permission.permission === 'ADMIN',
permissions = permissions.filter((permission) =>
MAINTENANCE_MODE_PERMISSIONS.includes(permission.permission),
);
}
return permissions;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/interfaces/uiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export type UiFlags = {
showUserDeviceCount?: boolean;
flagOverviewRedesign?: boolean;
licensedUsers?: boolean;
granularAdminPermissions?: boolean;
};

export interface IVersionInfo {
Expand Down
11 changes: 8 additions & 3 deletions src/lib/features/maintenance/maintenance-controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ADMIN, type IUnleashConfig, type IUnleashServices } from '../../types';
import {
ADMIN,
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';
Expand Down Expand Up @@ -38,7 +43,7 @@ export default class MaintenanceController extends Controller {
this.route({
method: 'post',
path: '',
permission: ADMIN,
permission: [ADMIN, UPDATE_MAINTENANCE_MODE],
handler: this.toggleMaintenance,
middleware: [
this.openApiService.validPath({
Expand All @@ -58,7 +63,7 @@ export default class MaintenanceController extends Controller {
this.route({
method: 'get',
path: '',
permission: ADMIN,
permission: [ADMIN, UPDATE_MAINTENANCE_MODE],
handler: this.getMaintenance,
middleware: [
this.openApiService.validPath({
Expand Down
5 changes: 5 additions & 0 deletions src/lib/types/experimental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export type IFlagKey =
| 'deleteStaleUserSessions'
| 'memorizeStats'
| 'licensedUsers'
| 'granularAdminPermissions'
| 'streaming'
| 'etagVariant';

Expand Down Expand Up @@ -281,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,
Expand Down
18 changes: 17 additions & 1 deletion src/lib/types/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -83,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],
},
{
Expand Down Expand Up @@ -141,4 +144,17 @@ export const ROOT_PERMISSION_CATEGORIES = [
RELEASE_PLAN_TEMPLATE_UPDATE,
],
},
{
label: 'Instance maintenance',
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,
Comment on lines +154 to +159
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work? Do you need one of them or all of them? Seems a little strange to gain access to the full admin panel if you have read client API token only? Maybe I'm misunderstanding how this works?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a way to selectively show some tabs (yet). It's a way to at least show all options, and PermissionGuard wrapper will do block further UI

image

];
1 change: 1 addition & 0 deletions src/server-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ process.nextTick(async () => {
showUserDeviceCount: true,
flagOverviewRedesign: false,
licensedUsers: true,
granularAdminPermissions: true,
},
},
authentication: {
Expand Down
Loading