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

[Securitysolution] Add Risk score missing privileges callout to enablement flyout #199804

Merged
merged 5 commits into from
Nov 14, 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
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { EntityStoreEnablementModal } from './enablement_modal';
import { useEntityEnginePrivileges } from '../hooks/use_entity_engine_privileges';
import { TestProviders } from '../../../../common/mock';
import type { EntityAnalyticsPrivileges } from '../../../../../common/api/entity_analytics';
import type { RiskEngineMissingPrivilegesResponse } from '../../../hooks/use_missing_risk_engine_privileges';

const mockToggle = jest.fn();
const mockEnableStore = jest.fn(() => jest.fn());

const mockUseEntityEnginePrivileges = jest.fn();
jest.mock('../hooks/use_entity_engine_privileges', () => ({
useEntityEnginePrivileges: jest.fn(),
useEntityEnginePrivileges: () => mockUseEntityEnginePrivileges(),
}));

const mockUseMissingRiskEnginePrivileges = jest.fn();
jest.mock('../../../hooks/use_missing_risk_engine_privileges', () => ({
useMissingRiskEnginePrivileges: () => mockUseMissingRiskEnginePrivileges(),
}));

const defaultProps = {
Expand All @@ -25,65 +33,144 @@ const defaultProps = {
entityStore: { disabled: false, checked: false },
};

const allEntityEnginePrivileges: EntityAnalyticsPrivileges = {
has_all_required: true,
privileges: {
elasticsearch: {
cluster: {
manage_enrich: true,
},
index: { 'logs-*': { read: false, view_index_metadata: true } },
},
kibana: {
'saved_object:entity-engine-status/all': true,
},
},
};

const missingEntityEnginePrivileges: EntityAnalyticsPrivileges = {
has_all_required: false,
privileges: {
elasticsearch: {
cluster: {
manage_enrich: false,
},
index: { 'logs-*': { read: false, view_index_metadata: false } },
},
kibana: {
'saved_object:entity-engine-status/all': false,
},
},
};

const allRiskEnginePrivileges: RiskEngineMissingPrivilegesResponse = {
hasAllRequiredPrivileges: true,
isLoading: false,
};

const missingRiskEnginePrivileges: RiskEngineMissingPrivilegesResponse = {
isLoading: false,
hasAllRequiredPrivileges: false,
missingPrivileges: {
clusterPrivileges: [],
indexPrivileges: [],
},
};

const renderComponent = (props = defaultProps) => {
return render(<EntityStoreEnablementModal {...props} />, { wrapper: TestProviders });
};

describe('EntityStoreEnablementModal', () => {
beforeEach(() => {
jest.clearAllMocks();
(useEntityEnginePrivileges as jest.Mock).mockReturnValue({
data: {
privileges: {
elasticsearch: {
index: {},
},
kibana: {},
},
},
isLoading: false,
});
});

it('should render the modal when visible is true', () => {
renderComponent();
expect(screen.getByRole('dialog')).toBeInTheDocument();
});
describe('with all privileges', () => {
beforeEach(() => {
mockUseEntityEnginePrivileges.mockReturnValue({
data: allEntityEnginePrivileges,
isLoading: false,
});

it('should not render the modal when visible is false', () => {
renderComponent({ ...defaultProps, visible: false });
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
mockUseMissingRiskEnginePrivileges.mockReturnValue(allRiskEnginePrivileges);
});

it('should call toggle function when cancel button is clicked', () => {
renderComponent();
fireEvent.click(screen.getByText('Cancel'));
expect(mockToggle).toHaveBeenCalledWith(false);
});
it('should render the modal when visible is true', () => {
renderComponent();
expect(screen.getByRole('dialog')).toBeInTheDocument();
});

it('should call enableStore function when enable button is clicked', () => {
renderComponent({
...defaultProps,
riskScore: { ...defaultProps.riskScore, checked: true },
entityStore: { ...defaultProps.entityStore, checked: true },
it('should not render the modal when visible is false', () => {
renderComponent({ ...defaultProps, visible: false });
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
fireEvent.click(screen.getByText('Enable'));
expect(mockEnableStore).toHaveBeenCalledWith({ riskScore: true, entityStore: true });
});

it('should display proceed warning when no enablement options are selected', () => {
renderComponent();
expect(screen.getByText('Please enable at least one option to proceed.')).toBeInTheDocument();
it('should call toggle function when cancel button is clicked', () => {
renderComponent();
fireEvent.click(screen.getByText('Cancel'));
expect(mockToggle).toHaveBeenCalledWith(false);
});

it('should call enableStore function when enable button is clicked', () => {
renderComponent({
...defaultProps,
riskScore: { ...defaultProps.riskScore, checked: true },
entityStore: { ...defaultProps.entityStore, checked: true },
});
fireEvent.click(screen.getByText('Enable'));
expect(mockEnableStore).toHaveBeenCalledWith({ riskScore: true, entityStore: true });
});

it('should display proceed warning when no enablement options are selected', () => {
renderComponent();
expect(screen.getByText('Please enable at least one option to proceed.')).toBeInTheDocument();
});

it('should disable the enable button when enablementOptions are false', () => {
renderComponent({
...defaultProps,
riskScore: { ...defaultProps.riskScore, checked: false },
entityStore: { ...defaultProps.entityStore, checked: false },
});

const enableButton = screen.getByRole('button', { name: /Enable/i });
expect(enableButton).toBeDisabled();
});

it('should not show entity engine missing privileges warning when no missing privileges', () => {
renderComponent();
expect(
screen.queryByTestId('callout-missing-entity-store-privileges')
).not.toBeInTheDocument();
});

it('should not show risk engine missing privileges warning when no missing privileges', () => {
renderComponent();
expect(
screen.queryByTestId('callout-missing-risk-engine-privileges')
).not.toBeInTheDocument();
});
});

it('should disable the enable button when enablementOptions are false', () => {
renderComponent({
...defaultProps,
riskScore: { ...defaultProps.riskScore, checked: false },
entityStore: { ...defaultProps.entityStore, checked: false },
describe('with no privileges', () => {
beforeEach(() => {
mockUseEntityEnginePrivileges.mockReturnValue({
data: missingEntityEnginePrivileges,
isLoading: false,
});

mockUseMissingRiskEnginePrivileges.mockReturnValue(missingRiskEnginePrivileges);
});

it('should show entity engine missing privileges warning when missing privileges', () => {
renderComponent();
expect(screen.getByTestId('callout-missing-entity-store-privileges')).toBeInTheDocument();
});

const enableButton = screen.getByRole('button', { name: /Enable/i });
expect(enableButton).toBeDisabled();
it('should show risk engine missing privileges warning when missing privileges', () => {
renderComponent();
expect(screen.getByTestId('callout-missing-risk-engine-privileges')).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import {
} from '../translations';
import { useEntityEnginePrivileges } from '../hooks/use_entity_engine_privileges';
import { MissingPrivilegesCallout } from './missing_privileges_callout';
import { useMissingRiskEnginePrivileges } from '../../../hooks/use_missing_risk_engine_privileges';
import { RiskEnginePrivilegesCallOut } from '../../risk_engine_privileges_callout';

export interface Enablements {
riskScore: boolean;
Expand Down Expand Up @@ -66,7 +68,9 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp
riskScore: !!riskScore.checked,
entityStore: !!entityStore.checked,
});
const { data: privileges, isLoading: isLoadingPrivileges } = useEntityEnginePrivileges();
const { data: entityEnginePrivileges, isLoading: isLoadingEntityEnginePrivileges } =
useEntityEnginePrivileges();
const riskEnginePrivileges = useMissingRiskEnginePrivileges();
const enablementOptions = enablements.riskScore || enablements.entityStore;

if (!visible) {
Expand Down Expand Up @@ -105,15 +109,22 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp
/>
}
checked={enablements.riskScore}
disabled={riskScore.disabled || false}
disabled={
riskScore.disabled ||
(!riskEnginePrivileges.isLoading && !riskEnginePrivileges?.hasAllRequiredPrivileges)
}
onChange={() => setEnablements((prev) => ({ ...prev, riskScore: !prev.riskScore }))}
/>
</EuiFlexItem>
{!riskEnginePrivileges.isLoading && !riskEnginePrivileges.hasAllRequiredPrivileges && (
<EuiFlexItem>
<RiskEnginePrivilegesCallOut privileges={riskEnginePrivileges} />
</EuiFlexItem>
)}
<EuiFlexItem>
<EuiText>{ENABLEMENT_DESCRIPTION_RISK_ENGINE_ONLY}</EuiText>
</EuiFlexItem>
<EuiHorizontalRule margin="none" />

<EuiFlexItem>
<EuiFlexGroup justifyContent="flexStart">
<EuiSwitch
Expand All @@ -125,7 +136,8 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp
}
checked={enablements.entityStore}
disabled={
entityStore.disabled || (!isLoadingPrivileges && !privileges?.has_all_required)
entityStore.disabled ||
(!isLoadingEntityEnginePrivileges && !entityEnginePrivileges?.has_all_required)
}
onChange={() =>
setEnablements((prev) => ({ ...prev, entityStore: !prev.entityStore }))
Expand All @@ -136,9 +148,9 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp
</EuiToolTip>
</EuiFlexGroup>
</EuiFlexItem>
{!privileges || privileges.has_all_required ? null : (
{!entityEnginePrivileges || entityEnginePrivileges.has_all_required ? null : (
<EuiFlexItem>
<MissingPrivilegesCallout privileges={privileges} />
<MissingPrivilegesCallout privileges={entityEnginePrivileges} />
</EuiFlexItem>
)}
<EuiFlexItem>
Expand Down