mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Cases] Add new sub feature privilege to prevent access to the cases settings page (#170635)
This commit is contained in:
parent
fcdd44ffeb
commit
56887ac1f8
89 changed files with 758 additions and 502 deletions
|
@ -99,6 +99,7 @@ export enum SecuritySubFeatureId {
|
|||
/** Sub-features IDs for Cases */
|
||||
export enum CasesSubFeatureId {
|
||||
deleteCases = 'deleteCasesSubFeature',
|
||||
casesSettings = 'casesSettingsSubFeature',
|
||||
}
|
||||
|
||||
/** Sub-features IDs for Security Assistant */
|
||||
|
|
|
@ -17,6 +17,7 @@ import type { CasesFeatureParams } from './types';
|
|||
*/
|
||||
export const getCasesBaseKibanaSubFeatureIds = (): CasesSubFeatureId[] => [
|
||||
CasesSubFeatureId.deleteCases,
|
||||
CasesSubFeatureId.casesSettings,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -60,7 +61,42 @@ export const getCasesSubFeaturesMap = ({
|
|||
],
|
||||
};
|
||||
|
||||
const casesSettingsCasesSubFeature: SubFeatureConfig = {
|
||||
name: i18n.translate(
|
||||
'securitySolutionPackages.features.featureRegistry.casesSettingsSubFeatureName',
|
||||
{
|
||||
defaultMessage: 'Case Settings',
|
||||
}
|
||||
),
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [
|
||||
{
|
||||
id: 'cases_settings',
|
||||
name: i18n.translate(
|
||||
'securitySolutionPackages.features.featureRegistry.casesSettingsSubFeatureDetails',
|
||||
{
|
||||
defaultMessage: 'Edit Case Settings',
|
||||
}
|
||||
),
|
||||
includeIn: 'all',
|
||||
savedObject: {
|
||||
all: [...savedObjects.files],
|
||||
read: [...savedObjects.files],
|
||||
},
|
||||
cases: {
|
||||
settings: [APP_ID],
|
||||
},
|
||||
ui: uiCapabilities.settings,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return new Map<CasesSubFeatureId, SubFeatureConfig>([
|
||||
[CasesSubFeatureId.deleteCases, deleteCasesSubFeature],
|
||||
[CasesSubFeatureId.casesSettings, casesSettingsCasesSubFeature],
|
||||
]);
|
||||
};
|
||||
|
|
|
@ -162,6 +162,7 @@ export const READ_CASES_CAPABILITY = 'read_cases' as const;
|
|||
export const UPDATE_CASES_CAPABILITY = 'update_cases' as const;
|
||||
export const DELETE_CASES_CAPABILITY = 'delete_cases' as const;
|
||||
export const PUSH_CASES_CAPABILITY = 'push_cases' as const;
|
||||
export const CASES_SETTINGS_CAPABILITY = 'cases_settings' as const;
|
||||
export const CASES_CONNECTORS_CAPABILITY = 'cases_connectors' as const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,6 +29,7 @@ export type {
|
|||
Ecs,
|
||||
CaseViewRefreshPropInterface,
|
||||
CasesPermissions,
|
||||
CasesCapabilities,
|
||||
CasesStatus,
|
||||
} from './ui/types';
|
||||
|
||||
|
@ -52,6 +53,7 @@ export {
|
|||
CASE_COMMENT_SAVED_OBJECT,
|
||||
CASES_CONNECTORS_CAPABILITY,
|
||||
GET_CONNECTORS_CONFIGURE_API_TAG,
|
||||
CASES_SETTINGS_CAPABILITY,
|
||||
} from './constants';
|
||||
|
||||
export type { AttachmentAttributes } from './types/domain';
|
||||
|
|
|
@ -12,7 +12,11 @@ import type {
|
|||
READ_CASES_CAPABILITY,
|
||||
UPDATE_CASES_CAPABILITY,
|
||||
} from '..';
|
||||
import type { CASES_CONNECTORS_CAPABILITY, PUSH_CASES_CAPABILITY } from '../constants';
|
||||
import type {
|
||||
CASES_CONNECTORS_CAPABILITY,
|
||||
CASES_SETTINGS_CAPABILITY,
|
||||
PUSH_CASES_CAPABILITY,
|
||||
} from '../constants';
|
||||
import type { SnakeToCamelCase } from '../types';
|
||||
import type {
|
||||
CaseSeverity,
|
||||
|
@ -299,6 +303,7 @@ export interface CasesPermissions {
|
|||
delete: boolean;
|
||||
push: boolean;
|
||||
connectors: boolean;
|
||||
settings: boolean;
|
||||
}
|
||||
|
||||
export interface CasesCapabilities {
|
||||
|
@ -308,4 +313,5 @@ export interface CasesCapabilities {
|
|||
[DELETE_CASES_CAPABILITY]: boolean;
|
||||
[PUSH_CASES_CAPABILITY]: boolean;
|
||||
[CASES_CONNECTORS_CAPABILITY]: boolean;
|
||||
[CASES_SETTINGS_CAPABILITY]: boolean;
|
||||
}
|
||||
|
|
34
x-pack/plugins/cases/common/utils/capabilities.test.tsx
Normal file
34
x-pack/plugins/cases/common/utils/capabilities.test.tsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { createUICapabilities } from './capabilities';
|
||||
|
||||
describe('createUICapabilities', () => {
|
||||
it('returns the UI capabilities correctly', () => {
|
||||
expect(createUICapabilities()).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"all": Array [
|
||||
"create_cases",
|
||||
"read_cases",
|
||||
"update_cases",
|
||||
"push_cases",
|
||||
"cases_connectors",
|
||||
],
|
||||
"delete": Array [
|
||||
"delete_cases",
|
||||
],
|
||||
"read": Array [
|
||||
"read_cases",
|
||||
"cases_connectors",
|
||||
],
|
||||
"settings": Array [
|
||||
"cases_settings",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -12,12 +12,14 @@ import {
|
|||
PUSH_CASES_CAPABILITY,
|
||||
READ_CASES_CAPABILITY,
|
||||
UPDATE_CASES_CAPABILITY,
|
||||
CASES_SETTINGS_CAPABILITY,
|
||||
} from '../constants';
|
||||
|
||||
export interface CasesUiCapabilities {
|
||||
all: readonly string[];
|
||||
read: readonly string[];
|
||||
delete: readonly string[];
|
||||
settings: readonly string[];
|
||||
}
|
||||
/**
|
||||
* Return the UI capabilities for each type of operation. These strings must match the values defined in the UI
|
||||
|
@ -33,4 +35,5 @@ export const createUICapabilities = (): CasesUiCapabilities => ({
|
|||
] as const,
|
||||
read: [READ_CASES_CAPABILITY, CASES_CONNECTORS_CAPABILITY] as const,
|
||||
delete: [DELETE_CASES_CAPABILITY] as const,
|
||||
settings: [CASES_SETTINGS_CAPABILITY] as const,
|
||||
});
|
||||
|
|
|
@ -40,10 +40,19 @@ export const canUseCases =
|
|||
acc.update = acc.update || userCapabilitiesForOwner.update;
|
||||
acc.delete = acc.delete || userCapabilitiesForOwner.delete;
|
||||
acc.push = acc.push || userCapabilitiesForOwner.push;
|
||||
const allFromAcc =
|
||||
acc.create && acc.read && acc.update && acc.delete && acc.push && acc.connectors;
|
||||
acc.all = acc.all || userCapabilitiesForOwner.all || allFromAcc;
|
||||
acc.connectors = acc.connectors || userCapabilitiesForOwner.connectors;
|
||||
acc.settings = acc.settings || userCapabilitiesForOwner.settings;
|
||||
|
||||
const allFromAcc =
|
||||
acc.create &&
|
||||
acc.read &&
|
||||
acc.update &&
|
||||
acc.delete &&
|
||||
acc.push &&
|
||||
acc.connectors &&
|
||||
acc.settings;
|
||||
|
||||
acc.all = acc.all || userCapabilitiesForOwner.all || allFromAcc;
|
||||
|
||||
return acc;
|
||||
},
|
||||
|
@ -55,6 +64,7 @@ export const canUseCases =
|
|||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
settings: false,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ describe('getUICapabilities', () => {
|
|||
"delete": false,
|
||||
"push": false,
|
||||
"read": false,
|
||||
"settings": false,
|
||||
"update": false,
|
||||
}
|
||||
`);
|
||||
|
@ -31,6 +32,7 @@ describe('getUICapabilities', () => {
|
|||
"delete": false,
|
||||
"push": false,
|
||||
"read": false,
|
||||
"settings": false,
|
||||
"update": false,
|
||||
}
|
||||
`);
|
||||
|
@ -45,6 +47,7 @@ describe('getUICapabilities', () => {
|
|||
"delete": false,
|
||||
"push": false,
|
||||
"read": false,
|
||||
"settings": false,
|
||||
"update": false,
|
||||
}
|
||||
`);
|
||||
|
@ -68,6 +71,7 @@ describe('getUICapabilities', () => {
|
|||
"delete": false,
|
||||
"push": false,
|
||||
"read": false,
|
||||
"settings": false,
|
||||
"update": false,
|
||||
}
|
||||
`);
|
||||
|
@ -82,6 +86,7 @@ describe('getUICapabilities', () => {
|
|||
"delete": false,
|
||||
"push": false,
|
||||
"read": false,
|
||||
"settings": false,
|
||||
"update": false,
|
||||
}
|
||||
`);
|
||||
|
@ -105,6 +110,7 @@ describe('getUICapabilities', () => {
|
|||
"delete": true,
|
||||
"push": true,
|
||||
"read": true,
|
||||
"settings": false,
|
||||
"update": true,
|
||||
}
|
||||
`);
|
||||
|
@ -113,23 +119,65 @@ describe('getUICapabilities', () => {
|
|||
it('returns false for the all field when cases_connectors is false', () => {
|
||||
expect(
|
||||
getUICapabilities({
|
||||
create_cases: false,
|
||||
create_cases: true,
|
||||
read_cases: true,
|
||||
update_cases: true,
|
||||
delete_cases: true,
|
||||
push_cases: true,
|
||||
cases_connectors: false,
|
||||
cases_settings: true,
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"all": false,
|
||||
"connectors": false,
|
||||
"create": false,
|
||||
"create": true,
|
||||
"delete": true,
|
||||
"push": true,
|
||||
"read": true,
|
||||
"settings": true,
|
||||
"update": true,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('returns false for the all field when cases_settings is false', () => {
|
||||
expect(
|
||||
getUICapabilities({
|
||||
create_cases: true,
|
||||
read_cases: true,
|
||||
update_cases: true,
|
||||
delete_cases: true,
|
||||
push_cases: true,
|
||||
cases_connectors: true,
|
||||
cases_settings: false,
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"all": false,
|
||||
"connectors": true,
|
||||
"create": true,
|
||||
"delete": true,
|
||||
"push": true,
|
||||
"read": true,
|
||||
"settings": false,
|
||||
"update": true,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('returns true for cases_settings when it is set to true in the ui capabilities', () => {
|
||||
expect(getUICapabilities({ cases_settings: true })).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"all": false,
|
||||
"connectors": false,
|
||||
"create": false,
|
||||
"delete": false,
|
||||
"push": false,
|
||||
"read": false,
|
||||
"settings": true,
|
||||
"update": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import type { CasesPermissions } from '../../../common';
|
||||
import {
|
||||
CASES_CONNECTORS_CAPABILITY,
|
||||
CASES_SETTINGS_CAPABILITY,
|
||||
CREATE_CASES_CAPABILITY,
|
||||
DELETE_CASES_CAPABILITY,
|
||||
PUSH_CASES_CAPABILITY,
|
||||
|
@ -24,7 +25,9 @@ export const getUICapabilities = (
|
|||
const deletePriv = !!featureCapabilities?.[DELETE_CASES_CAPABILITY];
|
||||
const push = !!featureCapabilities?.[PUSH_CASES_CAPABILITY];
|
||||
const connectors = !!featureCapabilities?.[CASES_CONNECTORS_CAPABILITY];
|
||||
const all = create && read && update && deletePriv && push && connectors;
|
||||
const settings = !!featureCapabilities?.[CASES_SETTINGS_CAPABILITY];
|
||||
|
||||
const all = create && read && update && deletePriv && push && connectors && settings;
|
||||
|
||||
return {
|
||||
all,
|
||||
|
@ -34,5 +37,6 @@ export const getUICapabilities = (
|
|||
delete: deletePriv,
|
||||
push,
|
||||
connectors,
|
||||
settings,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -194,6 +194,7 @@ export const useApplicationCapabilities = (): UseApplicationCapabilities => {
|
|||
delete: permissions.delete,
|
||||
push: permissions.push,
|
||||
connectors: permissions.connectors,
|
||||
settings: permissions.settings,
|
||||
},
|
||||
visualize: { crud: !!capabilities.visualize?.save, read: !!capabilities.visualize?.show },
|
||||
dashboard: {
|
||||
|
@ -215,6 +216,7 @@ export const useApplicationCapabilities = (): UseApplicationCapabilities => {
|
|||
permissions.delete,
|
||||
permissions.push,
|
||||
permissions.connectors,
|
||||
permissions.settings,
|
||||
]
|
||||
);
|
||||
};
|
||||
|
|
|
@ -75,6 +75,7 @@ export const createStartServicesMock = ({ license }: StartServiceArgs = {}): Sta
|
|||
delete_cases: true,
|
||||
push_cases: true,
|
||||
cases_connectors: true,
|
||||
cases_settings: true,
|
||||
},
|
||||
visualize: { save: true, show: true },
|
||||
dashboard: { show: true, createNew: true },
|
||||
|
|
|
@ -16,7 +16,9 @@ export const noCasesPermissions = () =>
|
|||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
settings: false,
|
||||
});
|
||||
|
||||
export const readCasesPermissions = () =>
|
||||
buildCasesPermissions({
|
||||
read: true,
|
||||
|
@ -25,6 +27,7 @@ export const readCasesPermissions = () =>
|
|||
delete: false,
|
||||
push: false,
|
||||
connectors: true,
|
||||
settings: false,
|
||||
});
|
||||
export const noCreateCasesPermissions = () => buildCasesPermissions({ create: false });
|
||||
export const noUpdateCasesPermissions = () => buildCasesPermissions({ update: false });
|
||||
|
@ -34,6 +37,7 @@ export const writeCasesPermissions = () => buildCasesPermissions({ read: false }
|
|||
export const onlyDeleteCasesPermission = () =>
|
||||
buildCasesPermissions({ read: false, create: false, update: false, delete: true, push: false });
|
||||
export const noConnectorsCasePermission = () => buildCasesPermissions({ connectors: false });
|
||||
export const noCasesSettingsPermission = () => buildCasesPermissions({ settings: false });
|
||||
|
||||
export const buildCasesPermissions = (overrides: Partial<Omit<CasesPermissions, 'all'>> = {}) => {
|
||||
const create = overrides.create ?? true;
|
||||
|
@ -42,7 +46,8 @@ export const buildCasesPermissions = (overrides: Partial<Omit<CasesPermissions,
|
|||
const deletePermissions = overrides.delete ?? true;
|
||||
const push = overrides.push ?? true;
|
||||
const connectors = overrides.connectors ?? true;
|
||||
const all = create && read && update && deletePermissions && push;
|
||||
const settings = overrides.settings ?? true;
|
||||
const all = create && read && update && deletePermissions && push && settings && connectors;
|
||||
|
||||
return {
|
||||
all,
|
||||
|
@ -52,6 +57,7 @@ export const buildCasesPermissions = (overrides: Partial<Omit<CasesPermissions,
|
|||
delete: deletePermissions,
|
||||
push,
|
||||
connectors,
|
||||
settings,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -64,6 +70,7 @@ export const noCasesCapabilities = () =>
|
|||
delete_cases: false,
|
||||
push_cases: false,
|
||||
cases_connectors: false,
|
||||
cases_settings: false,
|
||||
});
|
||||
export const readCasesCapabilities = () =>
|
||||
buildCasesCapabilities({
|
||||
|
@ -71,6 +78,7 @@ export const readCasesCapabilities = () =>
|
|||
update_cases: false,
|
||||
delete_cases: false,
|
||||
push_cases: false,
|
||||
cases_settings: false,
|
||||
});
|
||||
export const writeCasesCapabilities = () => {
|
||||
return buildCasesCapabilities({
|
||||
|
@ -86,5 +94,6 @@ export const buildCasesCapabilities = (overrides?: Partial<CasesCapabilities>) =
|
|||
delete_cases: overrides?.delete_cases ?? true,
|
||||
push_cases: overrides?.push_cases ?? true,
|
||||
cases_connectors: overrides?.cases_connectors ?? true,
|
||||
cases_settings: overrides?.cases_settings ?? true,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -46,9 +46,9 @@ describe('CasesTableHeader', () => {
|
|||
expect(result.getByTestId('configure-case-button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not display the configure button when the user does not have update privileges', () => {
|
||||
it('does not display the configure button when the user does not have settings privileges', () => {
|
||||
appMockRender = createAppMockRenderer({
|
||||
permissions: buildCasesPermissions({ update: false }),
|
||||
permissions: buildCasesPermissions({ settings: false }),
|
||||
});
|
||||
const result = appMockRender.render(<CasesTableHeader actionsErrors={[]} />);
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import type { AppMockRenderer } from '../../common/mock';
|
||||
import {
|
||||
createAppMockRenderer,
|
||||
noCasesSettingsPermission,
|
||||
noCreateCasesPermissions,
|
||||
buildCasesPermissions,
|
||||
} from '../../common/mock';
|
||||
import { NavButtons } from './nav_buttons';
|
||||
|
||||
describe('NavButtons', () => {
|
||||
let appMockRenderer: AppMockRenderer;
|
||||
|
||||
beforeEach(() => {
|
||||
appMockRenderer = createAppMockRenderer();
|
||||
});
|
||||
|
||||
it('shows the configure case button', () => {
|
||||
appMockRenderer.render(<NavButtons actionsErrors={[]} />);
|
||||
|
||||
expect(screen.getByTestId('configure-case-button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render the case create button with no create permissions', () => {
|
||||
appMockRenderer = createAppMockRenderer({ permissions: noCreateCasesPermissions() });
|
||||
appMockRenderer.render(<NavButtons actionsErrors={[]} />);
|
||||
|
||||
expect(screen.queryByTestId('createNewCaseBtn')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render the case configure button with no settings permissions', () => {
|
||||
appMockRenderer = createAppMockRenderer({ permissions: noCasesSettingsPermission() });
|
||||
appMockRenderer.render(<NavButtons actionsErrors={[]} />);
|
||||
|
||||
expect(screen.queryByTestId('configure-case-button')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render any button with no create and no settings permissions', () => {
|
||||
appMockRenderer = createAppMockRenderer({
|
||||
permissions: buildCasesPermissions({ create: false, settings: false }),
|
||||
});
|
||||
appMockRenderer.render(<NavButtons actionsErrors={[]} />);
|
||||
|
||||
expect(screen.queryByTestId('createNewCaseBtn')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('configure-case-button')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -43,14 +43,14 @@ export const NavButtons: FunctionComponent<Props> = ({ actionsErrors }) => {
|
|||
[navigateToCreateCase]
|
||||
);
|
||||
|
||||
if (!permissions.create && !permissions.update) {
|
||||
if (!permissions.create && !permissions.settings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexItem>
|
||||
<ButtonFlexGroup responsive={false}>
|
||||
{permissions.update && (
|
||||
{permissions.settings && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<ConfigureCaseButton
|
||||
label={i18n.CONFIGURE_CASES_BUTTON}
|
||||
|
|
|
@ -11,8 +11,8 @@ import type { MemoryRouterProps } from 'react-router';
|
|||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import {
|
||||
noCasesSettingsPermission,
|
||||
noCreateCasesPermissions,
|
||||
noUpdateCasesPermissions,
|
||||
readCasesPermissions,
|
||||
TestProviders,
|
||||
} from '../../common/mock';
|
||||
|
@ -96,14 +96,14 @@ describe('Cases routes', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Configure cases', () => {
|
||||
it('navigates to the configure cases page', () => {
|
||||
describe('Cases settings', () => {
|
||||
it('navigates to the cases settings page', () => {
|
||||
renderWithRouter(['/cases/configure']);
|
||||
expect(screen.getByText('Settings')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the no privileges page if the user does not have update privileges', () => {
|
||||
renderWithRouter(['/cases/configure'], noUpdateCasesPermissions());
|
||||
it('shows the no privileges page if the user does not have settings privileges', () => {
|
||||
renderWithRouter(['/cases/configure'], noCasesSettingsPermission());
|
||||
expect(screen.getByText('Privileges required')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -71,7 +71,7 @@ const CasesRoutesComponent: React.FC<CasesRoutesProps> = ({
|
|||
</Route>
|
||||
|
||||
<Route path={getCasesConfigurePath(basePath)}>
|
||||
{permissions.update ? (
|
||||
{permissions.settings ? (
|
||||
<ConfigureCases />
|
||||
) : (
|
||||
<NoPrivilegesPage pageName={i18n.CONFIGURE_CASES_PAGE_NAME} />
|
||||
|
|
|
@ -6,14 +6,18 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { screen } from '@testing-library/react';
|
||||
|
||||
import type { CallOutProps } from './callout';
|
||||
import { CallOut } from './callout';
|
||||
import { CLOSED_CASE_PUSH_ERROR_ID } from './types';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import type { AppMockRenderer } from '../../../common/mock';
|
||||
import { noCasesSettingsPermission, createAppMockRenderer } from '../../../common/mock';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
describe('Callout', () => {
|
||||
let appMockRenderer: AppMockRenderer;
|
||||
|
||||
const handleButtonClick = jest.fn();
|
||||
const defaultProps: CallOutProps = {
|
||||
id: 'md5-hex',
|
||||
|
@ -31,50 +35,19 @@ describe('Callout', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
appMockRenderer = createAppMockRenderer();
|
||||
});
|
||||
|
||||
it('It renders the callout', () => {
|
||||
const wrapper = mount(<CallOut {...defaultProps} />);
|
||||
expect(wrapper.find(`[data-test-subj="case-callout-md5-hex"]`).exists()).toBeTruthy();
|
||||
expect(wrapper.find(`[data-test-subj="callout-messages-md5-hex"]`).exists()).toBeTruthy();
|
||||
expect(wrapper.find(`[data-test-subj="callout-onclick-md5-hex"]`).exists()).toBeTruthy();
|
||||
appMockRenderer.render(<CallOut {...defaultProps} />);
|
||||
expect(screen.getByTestId('case-callout-md5-hex')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('callout-messages-md5-hex')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('callout-onclick-md5-hex')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not shows any messages when the list is empty', () => {
|
||||
const wrapper = mount(<CallOut {...defaultProps} messages={[]} />);
|
||||
expect(wrapper.find(`[data-test-subj="callout-messages-md5-hex"]`).exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('transform the button color correctly - primary', () => {
|
||||
const wrapper = mount(<CallOut {...defaultProps} />);
|
||||
const className =
|
||||
wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).first().prop('className') ??
|
||||
'';
|
||||
expect(className.includes('primary')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('transform the button color correctly - success', () => {
|
||||
const wrapper = mount(<CallOut {...defaultProps} type={'success'} />);
|
||||
const className =
|
||||
wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).first().prop('className') ??
|
||||
'';
|
||||
expect(className.includes('success')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('transform the button color correctly - warning', () => {
|
||||
const wrapper = mount(<CallOut {...defaultProps} type={'warning'} />);
|
||||
const className =
|
||||
wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).first().prop('className') ??
|
||||
'';
|
||||
expect(className.includes('warning')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('transform the button color correctly - danger', () => {
|
||||
const wrapper = mount(<CallOut {...defaultProps} type={'danger'} />);
|
||||
const className =
|
||||
wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).first().prop('className') ??
|
||||
'';
|
||||
expect(className.includes('danger')).toBeTruthy();
|
||||
appMockRenderer.render(<CallOut {...defaultProps} messages={[]} />);
|
||||
expect(screen.queryByTestId('callout-messages-md5-hex')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show the button when case is closed error is present', () => {
|
||||
|
@ -89,15 +62,9 @@ describe('Callout', () => {
|
|||
],
|
||||
};
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<CallOut {...props} />
|
||||
</TestProviders>
|
||||
);
|
||||
appMockRenderer.render(<CallOut {...props} />);
|
||||
|
||||
expect(wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).exists()).toEqual(
|
||||
false
|
||||
);
|
||||
expect(screen.queryByTestId('callout-onclick-md5-hex')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show the button when license error is present', () => {
|
||||
|
@ -106,22 +73,27 @@ describe('Callout', () => {
|
|||
hasLicenseError: true,
|
||||
};
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<CallOut {...props} />
|
||||
</TestProviders>
|
||||
);
|
||||
appMockRenderer.render(<CallOut {...props} />);
|
||||
|
||||
expect(wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).exists()).toEqual(
|
||||
false
|
||||
);
|
||||
expect(screen.queryByTestId('callout-onclick-md5-hex')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show the button with no settings permissions', () => {
|
||||
appMockRenderer = createAppMockRenderer({ permissions: noCasesSettingsPermission() });
|
||||
|
||||
appMockRenderer.render(<CallOut {...defaultProps} />);
|
||||
|
||||
expect(screen.queryByTestId('callout-onclick-md5-hex')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// use this for storage if we ever want to bring that back
|
||||
it('onClick passes id and type', () => {
|
||||
const wrapper = mount(<CallOut {...defaultProps} />);
|
||||
expect(wrapper.find(`[data-test-subj="callout-onclick-md5-hex"]`).exists()).toBeTruthy();
|
||||
wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).simulate('click');
|
||||
appMockRenderer.render(<CallOut {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('callout-onclick-md5-hex')).toBeInTheDocument();
|
||||
|
||||
userEvent.click(screen.getByTestId('callout-onclick-md5-hex'));
|
||||
|
||||
expect(handleButtonClick.mock.calls[0][1]).toEqual('md5-hex');
|
||||
expect(handleButtonClick.mock.calls[0][2]).toEqual('primary');
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ import React, { memo, useCallback, useMemo } from 'react';
|
|||
import type { ErrorMessage } from './types';
|
||||
import { CLOSED_CASE_PUSH_ERROR_ID } from './types';
|
||||
import * as i18n from './translations';
|
||||
import { useCasesContext } from '../../cases_context/use_cases_context';
|
||||
|
||||
export interface CallOutProps {
|
||||
handleButtonClick: (
|
||||
|
@ -32,6 +33,8 @@ const CallOutComponent = ({
|
|||
type,
|
||||
hasLicenseError,
|
||||
}: CallOutProps) => {
|
||||
const { permissions } = useCasesContext();
|
||||
|
||||
const handleCallOut = useCallback(
|
||||
(e) => handleButtonClick(e, id, type),
|
||||
[handleButtonClick, id, type]
|
||||
|
@ -57,7 +60,7 @@ const CallOutComponent = ({
|
|||
size="s"
|
||||
>
|
||||
<EuiDescriptionList data-test-subj={`callout-messages-${id}`} listItems={messages} />
|
||||
{!isCaseClosed && !hasLicenseError && (
|
||||
{!isCaseClosed && !hasLicenseError && permissions.settings && (
|
||||
<EuiButton
|
||||
data-test-subj={`callout-onclick-${id}`}
|
||||
color={type === 'success' ? 'success' : type}
|
||||
|
|
|
@ -46,6 +46,8 @@ const helpersMock: jest.Mocked<CasesUiStart['helpers']> = {
|
|||
update: false,
|
||||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
settings: false,
|
||||
}),
|
||||
getRuleIdFromEvent: jest.fn(),
|
||||
groupAlertsByRule: jest.fn(),
|
||||
|
|
|
@ -100,6 +100,33 @@ export const getCasesKibanaFeature = (): KibanaFeatureConfig => {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n.translate('xpack.cases.features.casesSettingsSubFeatureName', {
|
||||
defaultMessage: 'Case Settings',
|
||||
}),
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [
|
||||
{
|
||||
id: 'cases_settings',
|
||||
name: i18n.translate('xpack.cases.features.casesSettingsSubFeatureDetails', {
|
||||
defaultMessage: 'Edit Case Settings',
|
||||
}),
|
||||
includeIn: 'all',
|
||||
savedObject: {
|
||||
all: [...filesSavedObjectTypes],
|
||||
read: [...filesSavedObjectTypes],
|
||||
},
|
||||
cases: {
|
||||
settings: [APP_ID],
|
||||
},
|
||||
ui: capabilities.settings,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
|
|
@ -12,8 +12,6 @@ import { sampleAttribute } from '../../configurations/test_data/sample_attribute
|
|||
import * as pluginHook from '../../../../../hooks/use_plugin_context';
|
||||
import { TypedLensByValueInput } from '@kbn/lens-plugin/public';
|
||||
import { ExpViewActionMenuContent } from './action_menu';
|
||||
import { noCasesPermissions as mockUseGetCasesPermissions } from '@kbn/observability-shared-plugin/public';
|
||||
import * as obsHooks from '@kbn/observability-shared-plugin/public/hooks/use_get_user_cases_permissions';
|
||||
|
||||
jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({
|
||||
appMountParameters: {
|
||||
|
@ -21,13 +19,6 @@ jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({
|
|||
},
|
||||
} as any);
|
||||
|
||||
jest.spyOn(obsHooks, 'useGetUserCasesPermissions').mockImplementation(
|
||||
() =>
|
||||
({
|
||||
useGetUserCasesPermissions: jest.fn(() => mockUseGetCasesPermissions()),
|
||||
} as any)
|
||||
);
|
||||
|
||||
describe('Action Menu', function () {
|
||||
afterAll(() => {
|
||||
jest.clearAllMocks();
|
||||
|
|
|
@ -12,8 +12,6 @@ import { ExploratoryView } from './exploratory_view';
|
|||
import * as obsvDataViews from '../../../utils/observability_data_views/observability_data_views';
|
||||
import * as pluginHook from '../../../hooks/use_plugin_context';
|
||||
import { createStubIndexPattern } from '@kbn/data-plugin/common/stubs';
|
||||
import { noCasesPermissions as mockUseGetCasesPermissions } from '@kbn/observability-shared-plugin/public/utils/cases_permissions';
|
||||
import * as obsHooks from '@kbn/observability-shared-plugin/public/hooks/use_get_user_cases_permissions';
|
||||
|
||||
jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({
|
||||
appMountParameters: {
|
||||
|
@ -21,13 +19,6 @@ jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({
|
|||
},
|
||||
} as any);
|
||||
|
||||
jest.spyOn(obsHooks, 'useGetUserCasesPermissions').mockImplementation(
|
||||
() =>
|
||||
({
|
||||
useGetUserCasesPermissions: jest.fn(() => mockUseGetCasesPermissions()),
|
||||
} as any)
|
||||
);
|
||||
|
||||
describe('ExploratoryView', () => {
|
||||
mockAppDataView();
|
||||
|
||||
|
|
|
@ -13,10 +13,15 @@ import * as useCaseHook from '../hooks/use_add_to_case';
|
|||
import * as datePicker from '../components/date_range_picker';
|
||||
import moment from 'moment';
|
||||
import { noCasesPermissions as mockUseGetCasesPermissions } from '@kbn/observability-shared-plugin/public';
|
||||
import * as obsHooks from '@kbn/observability-shared-plugin/public/hooks/use_get_user_cases_permissions';
|
||||
|
||||
jest.spyOn(obsHooks, 'useGetUserCasesPermissions').mockReturnValue(mockUseGetCasesPermissions());
|
||||
describe('AddToCaseAction', function () {
|
||||
const coreRenderProps = {
|
||||
cases: {
|
||||
ui: { getAllCasesSelectorModal: jest.fn() },
|
||||
helpers: { canUseCases: () => mockUseGetCasesPermissions() },
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(datePicker, 'parseRelativeDate').mockRestore();
|
||||
});
|
||||
|
@ -26,7 +31,8 @@ describe('AddToCaseAction', function () {
|
|||
<AddToCaseAction
|
||||
lensAttributes={{ title: 'Performance distribution' } as any}
|
||||
timeRange={{ to: 'now', from: 'now-5m' }}
|
||||
/>
|
||||
/>,
|
||||
{ core: coreRenderProps }
|
||||
);
|
||||
expect(await findByText('Add to case')).toBeInTheDocument();
|
||||
});
|
||||
|
@ -39,7 +45,8 @@ describe('AddToCaseAction', function () {
|
|||
<AddToCaseAction
|
||||
lensAttributes={{ title: 'Performance distribution' } as any}
|
||||
timeRange={{ to: 'now', from: 'now-5m' }}
|
||||
/>
|
||||
/>,
|
||||
{ core: coreRenderProps }
|
||||
);
|
||||
expect(await findByText('Add to case')).toBeInTheDocument();
|
||||
|
||||
|
@ -60,7 +67,8 @@ describe('AddToCaseAction', function () {
|
|||
const useAddToCaseHook = jest.spyOn(useCaseHook, 'useAddToCase');
|
||||
|
||||
const { getByText } = render(
|
||||
<AddToCaseAction lensAttributes={null} timeRange={{ to: '', from: '' }} owner="security" />
|
||||
<AddToCaseAction lensAttributes={null} timeRange={{ to: '', from: '' }} owner="security" />,
|
||||
{ core: coreRenderProps }
|
||||
);
|
||||
|
||||
expect(await forNearestButton(getByText)('Add to case')).toBeDisabled();
|
||||
|
@ -95,7 +103,7 @@ describe('AddToCaseAction', function () {
|
|||
lensAttributes={{ title: 'Performance distribution' } as any}
|
||||
timeRange={{ to: 'now', from: 'now-5m' }}
|
||||
/>,
|
||||
{ initSeries }
|
||||
{ initSeries, core: coreRenderProps }
|
||||
);
|
||||
fireEvent.click(await findByText('Add to case'));
|
||||
|
||||
|
@ -111,6 +119,7 @@ describe('AddToCaseAction', function () {
|
|||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
settings: false,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
|
|
@ -16,7 +16,6 @@ import {
|
|||
} from '@kbn/cases-plugin/public';
|
||||
import { TypedLensByValueInput } from '@kbn/lens-plugin/public';
|
||||
import { observabilityFeatureId } from '@kbn/observability-shared-plugin/public';
|
||||
import { useGetUserCasesPermissions } from '@kbn/observability-shared-plugin/public';
|
||||
import { ObservabilityAppServices } from '../../../../application/types';
|
||||
import { useAddToCase } from '../hooks/use_add_to_case';
|
||||
import { parseRelativeDate } from '../components/date_range_picker';
|
||||
|
@ -37,7 +36,7 @@ export function AddToCaseAction({
|
|||
timeRange,
|
||||
}: AddToCaseProps) {
|
||||
const kServices = useKibana<ObservabilityAppServices>().services;
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const userCasesPermissions = kServices.cases.helpers.canUseCases([observabilityFeatureId]);
|
||||
|
||||
const {
|
||||
cases,
|
||||
|
|
|
@ -204,6 +204,16 @@ export interface FeatureKibanaPrivileges {
|
|||
* ```
|
||||
*/
|
||||
delete?: readonly string[];
|
||||
/**
|
||||
* List of case owners which users should have settings access to when granted this privilege.
|
||||
* @example
|
||||
* ```ts
|
||||
* {
|
||||
* settings: ['securitySolution']
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
settings?: readonly string[];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -558,6 +558,7 @@ Array [
|
|||
"delete": Array [],
|
||||
"push": Array [],
|
||||
"read": Array [],
|
||||
"settings": Array [],
|
||||
"update": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
|
@ -710,6 +711,7 @@ Array [
|
|||
"delete": Array [],
|
||||
"push": Array [],
|
||||
"read": Array [],
|
||||
"settings": Array [],
|
||||
"update": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
|
@ -1032,6 +1034,7 @@ Array [
|
|||
"delete": Array [],
|
||||
"push": Array [],
|
||||
"read": Array [],
|
||||
"settings": Array [],
|
||||
"update": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
|
@ -1169,6 +1172,7 @@ Array [
|
|||
"delete": Array [],
|
||||
"push": Array [],
|
||||
"read": Array [],
|
||||
"settings": Array [],
|
||||
"update": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
|
@ -1321,6 +1325,7 @@ Array [
|
|||
"delete": Array [],
|
||||
"push": Array [],
|
||||
"read": Array [],
|
||||
"settings": Array [],
|
||||
"update": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
|
@ -1643,6 +1648,7 @@ Array [
|
|||
"delete": Array [],
|
||||
"push": Array [],
|
||||
"read": Array [],
|
||||
"settings": Array [],
|
||||
"update": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
|
|
|
@ -77,6 +77,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -146,6 +147,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -214,6 +216,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -284,6 +287,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -324,6 +328,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -385,6 +390,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-sub-type'],
|
||||
delete: ['cases-delete-sub-type'],
|
||||
push: ['cases-push-sub-type'],
|
||||
settings: ['cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
|
@ -431,6 +437,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -498,6 +505,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -559,6 +567,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-sub-type'],
|
||||
delete: ['cases-delete-sub-type'],
|
||||
push: ['cases-push-sub-type'],
|
||||
settings: ['cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
|
@ -605,6 +614,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -672,6 +682,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -734,6 +745,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-sub-type'],
|
||||
delete: ['cases-delete-sub-type'],
|
||||
push: ['cases-push-sub-type'],
|
||||
settings: ['cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
|
@ -783,6 +795,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type', 'cases-update-sub-type'],
|
||||
delete: ['cases-delete-type', 'cases-delete-sub-type'],
|
||||
push: ['cases-push-type', 'cases-push-sub-type'],
|
||||
settings: ['cases-settings-type', 'cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-action', 'ui-sub-type'],
|
||||
},
|
||||
|
@ -818,6 +831,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-sub-type'],
|
||||
delete: ['cases-delete-sub-type'],
|
||||
push: ['cases-push-sub-type'],
|
||||
settings: ['cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-action', 'ui-sub-type'],
|
||||
},
|
||||
|
@ -860,6 +874,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -964,6 +979,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -998,6 +1014,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: [],
|
||||
delete: [],
|
||||
push: [],
|
||||
settings: [],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -1038,6 +1055,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -1100,6 +1118,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-sub-type'],
|
||||
delete: ['cases-delete-sub-type'],
|
||||
push: ['cases-push-sub-type'],
|
||||
settings: ['cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
|
@ -1149,6 +1168,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type', 'cases-update-sub-type'],
|
||||
delete: ['cases-delete-type', 'cases-delete-sub-type'],
|
||||
push: ['cases-push-type', 'cases-push-sub-type'],
|
||||
settings: ['cases-settings-type', 'cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-action', 'ui-sub-type'],
|
||||
},
|
||||
|
@ -1341,6 +1361,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-sub-type'],
|
||||
delete: ['cases-delete-sub-type'],
|
||||
push: ['cases-push-sub-type'],
|
||||
settings: ['cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
|
@ -1390,6 +1411,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-sub-type'],
|
||||
delete: ['cases-delete-sub-type'],
|
||||
push: ['cases-push-sub-type'],
|
||||
settings: ['cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
|
@ -1425,6 +1447,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-sub-type'],
|
||||
delete: ['cases-delete-sub-type'],
|
||||
push: ['cases-push-sub-type'],
|
||||
settings: ['cases-settings-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
|
@ -1465,6 +1488,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -1555,6 +1579,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: ['cases-update-type'],
|
||||
delete: ['cases-delete-type'],
|
||||
push: ['cases-push-type'],
|
||||
settings: ['cases-settings-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
@ -1589,6 +1614,7 @@ describe('featurePrivilegeIterator', () => {
|
|||
update: [],
|
||||
delete: [],
|
||||
push: [],
|
||||
settings: [],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
|
|
|
@ -147,6 +147,10 @@ function mergeWithSubFeatures(
|
|||
subFeaturePrivilege.cases?.delete ?? []
|
||||
),
|
||||
push: mergeArrays(mergedConfig.cases?.push ?? [], subFeaturePrivilege.cases?.push ?? []),
|
||||
settings: mergeArrays(
|
||||
mergedConfig.cases?.settings ?? [],
|
||||
subFeaturePrivilege.cases?.settings ?? []
|
||||
),
|
||||
};
|
||||
}
|
||||
return mergedConfig;
|
||||
|
|
|
@ -82,6 +82,7 @@ const casesSchemaObject = schema.maybe(
|
|||
update: schema.maybe(casesSchema),
|
||||
delete: schema.maybe(casesSchema),
|
||||
push: schema.maybe(casesSchema),
|
||||
settings: schema.maybe(casesSchema),
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CasesPermissions } from '@kbn/cases-plugin/common';
|
||||
import { useKibana } from '../utils/kibana_react';
|
||||
import { casesFeatureId } from '../../common';
|
||||
|
||||
export function useGetUserCasesPermissions() {
|
||||
const [casesPermissions, setCasesPermissions] = useState<CasesPermissions>({
|
||||
all: false,
|
||||
read: false,
|
||||
create: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
});
|
||||
const uiCapabilities = useKibana().services.application.capabilities;
|
||||
|
||||
const casesCapabilities = useKibana().services.cases.helpers.getUICapabilities(
|
||||
uiCapabilities[casesFeatureId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setCasesPermissions({
|
||||
all: casesCapabilities.all,
|
||||
create: casesCapabilities.create,
|
||||
read: casesCapabilities.read,
|
||||
update: casesCapabilities.update,
|
||||
delete: casesCapabilities.delete,
|
||||
push: casesCapabilities.push,
|
||||
connectors: casesCapabilities.connectors,
|
||||
});
|
||||
}, [
|
||||
casesCapabilities.all,
|
||||
casesCapabilities.create,
|
||||
casesCapabilities.read,
|
||||
casesCapabilities.update,
|
||||
casesCapabilities.delete,
|
||||
casesCapabilities.push,
|
||||
casesCapabilities.connectors,
|
||||
]);
|
||||
|
||||
return casesPermissions;
|
||||
}
|
|
@ -76,16 +76,6 @@ jest.mock('../../hooks/use_fetch_rule', () => {
|
|||
};
|
||||
});
|
||||
jest.mock('@kbn/observability-shared-plugin/public');
|
||||
jest.mock('../../hooks/use_get_user_cases_permissions', () => ({
|
||||
useGetUserCasesPermissions: () => ({
|
||||
all: true,
|
||||
create: true,
|
||||
delete: true,
|
||||
push: true,
|
||||
read: true,
|
||||
update: true,
|
||||
}),
|
||||
}));
|
||||
|
||||
const useFetchAlertDetailMock = useFetchAlertDetail as jest.Mock;
|
||||
const useParamsMock = useParams as jest.Mock;
|
||||
|
|
|
@ -58,7 +58,7 @@ export function AlertDetails() {
|
|||
const [isLoading, alert] = useFetchAlertDetail(alertId);
|
||||
const [ruleTypeModel, setRuleTypeModel] = useState<RuleTypeModel | null>(null);
|
||||
const CasesContext = getCasesContext();
|
||||
const userCasesPermissions = canUseCases();
|
||||
const userCasesPermissions = canUseCases([observabilityFeatureId]);
|
||||
const { rule } = useFetchRule({
|
||||
ruleId: alert?.fields[ALERT_RULE_UUID],
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ import * as pluginContext from '../../../hooks/use_plugin_context';
|
|||
import { ConfigSchema, ObservabilityPublicPluginsStart } from '../../../plugin';
|
||||
import { AppMountParameters, CoreStart } from '@kbn/core/public';
|
||||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||
import { allCasesPermissions, noCasesPermissions } from '@kbn/observability-shared-plugin/public';
|
||||
|
||||
const refresh = jest.fn();
|
||||
const caseHooksReturnedValue = {
|
||||
|
@ -36,15 +37,13 @@ mockUseKibanaReturnValue.services.cases.hooks.useCasesAddToExistingCaseModal.moc
|
|||
caseHooksReturnedValue
|
||||
);
|
||||
|
||||
mockUseKibanaReturnValue.services.cases.helpers.canUseCases.mockReturnValue(allCasesPermissions());
|
||||
|
||||
jest.mock('../../../utils/kibana_react', () => ({
|
||||
__esModule: true,
|
||||
useKibana: jest.fn(() => mockUseKibanaReturnValue),
|
||||
}));
|
||||
|
||||
jest.mock('../../../hooks/use_get_user_cases_permissions', () => ({
|
||||
useGetUserCasesPermissions: jest.fn(() => ({ create: true, read: true })),
|
||||
}));
|
||||
|
||||
jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana/kibana_react', () => ({
|
||||
useKibana: jest.fn(() => ({
|
||||
services: { notifications: { toasts: { addDanger: jest.fn(), addSuccess: jest.fn() } } },
|
||||
|
@ -175,4 +174,18 @@ describe('ObservabilityActions component', () => {
|
|||
|
||||
expect(refresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should hide the case actions without permissions', async () => {
|
||||
mockUseKibanaReturnValue.services.cases.helpers.canUseCases.mockReturnValue(
|
||||
noCasesPermissions()
|
||||
);
|
||||
|
||||
const wrapper = await setup('nothing');
|
||||
wrapper.find('[data-test-subj="alertsTableRowActionMore"]').hostNodes().simulate('click');
|
||||
|
||||
expect(wrapper.find('[data-test-subj="add-to-new-case-action"]').hostNodes().length).toBe(0);
|
||||
expect(wrapper.find('[data-test-subj="add-to-existing-case-action"]').hostNodes().length).toBe(
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -30,12 +30,11 @@ import {
|
|||
} from '@kbn/rule-data-utils';
|
||||
import { useBulkUntrackAlerts } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { useKibana } from '../../../utils/kibana_react';
|
||||
import { useGetUserCasesPermissions } from '../../../hooks/use_get_user_cases_permissions';
|
||||
import { isAlertDetailsEnabledPerApp } from '../../../utils/is_alert_details_enabled';
|
||||
import { parseAlert } from '../helpers/parse_alert';
|
||||
import { paths } from '../../../../common/locators/paths';
|
||||
import { RULE_DETAILS_PAGE_ID } from '../../rule_details/constants';
|
||||
import type { ObservabilityRuleTypeRegistry } from '../../..';
|
||||
import { observabilityFeatureId, ObservabilityRuleTypeRegistry } from '../../..';
|
||||
import type { ConfigSchema } from '../../../plugin';
|
||||
import type { TopAlert } from '../../../typings/alerts';
|
||||
|
||||
|
@ -62,15 +61,15 @@ export function AlertActions({
|
|||
}: Props) {
|
||||
const {
|
||||
cases: {
|
||||
helpers: { getRuleIdFromEvent },
|
||||
helpers: { getRuleIdFromEvent, canUseCases },
|
||||
hooks: { useCasesAddToNewCaseFlyout, useCasesAddToExistingCaseModal },
|
||||
},
|
||||
http: {
|
||||
basePath: { prepend },
|
||||
},
|
||||
} = useKibana().services;
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const { mutateAsync: untrackAlerts } = useBulkUntrackAlerts();
|
||||
const userCasesPermissions = canUseCases([observabilityFeatureId]);
|
||||
|
||||
const parseObservabilityAlert = useMemo(
|
||||
() => parseAlert(observabilityRuleTypeRegistry),
|
||||
|
|
|
@ -7,15 +7,17 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { useGetUserCasesPermissions } from '../../hooks/use_get_user_cases_permissions';
|
||||
import { observabilityFeatureId } from '../../../common';
|
||||
import { usePluginContext } from '../../hooks/use_plugin_context';
|
||||
import { Cases } from './components/cases';
|
||||
import { CaseFeatureNoPermissions } from './components/feature_no_permissions';
|
||||
import { HeaderMenu } from '../overview/components/header_menu/header_menu';
|
||||
import { useKibana } from '../../utils/kibana_react';
|
||||
|
||||
export function CasesPage() {
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const { ObservabilityPageTemplate } = usePluginContext();
|
||||
const { canUseCases } = useKibana().services.cases.helpers;
|
||||
const userCasesPermissions = canUseCases([observabilityFeatureId]);
|
||||
|
||||
return userCasesPermissions.read ? (
|
||||
<ObservabilityPageTemplate isPageDataLoaded data-test-subj="o11yCasesPage">
|
||||
|
|
|
@ -27,6 +27,7 @@ const defaultProps: CasesProps = {
|
|||
push: true,
|
||||
update: true,
|
||||
connectors: true,
|
||||
settings: true,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -43,5 +44,6 @@ CasesPageWithNoPermissions.args = {
|
|||
push: false,
|
||||
update: false,
|
||||
connectors: false,
|
||||
settings: false,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export const noCasesPermissions = () => ({
|
||||
all: false,
|
||||
create: false,
|
||||
read: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
push: false,
|
||||
});
|
|
@ -175,6 +175,36 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n.translate('xpack.observability.featureRegistry.casesSettingsSubFeatureName', {
|
||||
defaultMessage: 'Case Settings',
|
||||
}),
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [
|
||||
{
|
||||
id: 'cases_settings',
|
||||
name: i18n.translate(
|
||||
'xpack.observability.featureRegistry.casesSettingsSubFeatureDetails',
|
||||
{
|
||||
defaultMessage: 'Edit Case Settings',
|
||||
}
|
||||
),
|
||||
includeIn: 'all',
|
||||
savedObject: {
|
||||
all: [...filesSavedObjectTypes],
|
||||
read: [...filesSavedObjectTypes],
|
||||
},
|
||||
cases: {
|
||||
settings: [observabilityFeatureId],
|
||||
},
|
||||
ui: casesCapabilities.settings,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CasesPermissions } from '@kbn/cases-plugin/common';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { casesFeatureId } from '../../common';
|
||||
import { ObservabilitySharedStart } from '../plugin';
|
||||
|
||||
export function useGetUserCasesPermissions() {
|
||||
const [casesPermissions, setCasesPermissions] = useState<CasesPermissions>({
|
||||
all: false,
|
||||
read: false,
|
||||
create: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
});
|
||||
const uiCapabilities = useKibana().services.application!.capabilities;
|
||||
|
||||
const casesCapabilities =
|
||||
useKibana<ObservabilitySharedStart>().services.cases.helpers.getUICapabilities(
|
||||
uiCapabilities[casesFeatureId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setCasesPermissions({
|
||||
all: casesCapabilities.all,
|
||||
create: casesCapabilities.create,
|
||||
read: casesCapabilities.read,
|
||||
update: casesCapabilities.update,
|
||||
delete: casesCapabilities.delete,
|
||||
push: casesCapabilities.push,
|
||||
connectors: casesCapabilities.connectors,
|
||||
});
|
||||
}, [
|
||||
casesCapabilities.all,
|
||||
casesCapabilities.create,
|
||||
casesCapabilities.read,
|
||||
casesCapabilities.update,
|
||||
casesCapabilities.delete,
|
||||
casesCapabilities.push,
|
||||
casesCapabilities.connectors,
|
||||
]);
|
||||
|
||||
return casesPermissions;
|
||||
}
|
|
@ -57,7 +57,6 @@ export {
|
|||
} from './hooks/use_track_metric';
|
||||
export type { TrackEvent } from './hooks/use_track_metric';
|
||||
export { useQuickTimeRanges } from './hooks/use_quick_time_ranges';
|
||||
export { useGetUserCasesPermissions } from './hooks/use_get_user_cases_permissions';
|
||||
export { useTimeZone } from './hooks/use_time_zone';
|
||||
export { useChartTheme } from './hooks/use_chart_theme';
|
||||
export { useLinkProps, shouldHandleLinkEvent } from './hooks/use_link_props';
|
||||
|
@ -66,7 +65,7 @@ export { NavigationWarningPromptProvider, Prompt } from './components/navigation
|
|||
|
||||
export type { ApmIndicesConfig, UXMetrics } from './types';
|
||||
|
||||
export { noCasesPermissions } from './utils/cases_permissions';
|
||||
export { noCasesPermissions, allCasesPermissions } from './utils/cases_permissions';
|
||||
|
||||
export {
|
||||
type ObservabilityActionContextMenuItemProps,
|
||||
|
|
|
@ -13,4 +13,16 @@ export const noCasesPermissions = () => ({
|
|||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
settings: false,
|
||||
});
|
||||
|
||||
export const allCasesPermissions = () => ({
|
||||
all: true,
|
||||
create: true,
|
||||
read: true,
|
||||
update: true,
|
||||
delete: true,
|
||||
push: true,
|
||||
connectors: true,
|
||||
settings: true,
|
||||
});
|
||||
|
|
|
@ -5,7 +5,6 @@ Array [
|
|||
"cases:observability/pushCase",
|
||||
"cases:observability/createCase",
|
||||
"cases:observability/createComment",
|
||||
"cases:observability/createConfiguration",
|
||||
"cases:observability/getCase",
|
||||
"cases:observability/getComment",
|
||||
"cases:observability/getTags",
|
||||
|
@ -14,9 +13,10 @@ Array [
|
|||
"cases:observability/findConfigurations",
|
||||
"cases:observability/updateCase",
|
||||
"cases:observability/updateComment",
|
||||
"cases:observability/updateConfiguration",
|
||||
"cases:observability/deleteCase",
|
||||
"cases:observability/deleteComment",
|
||||
"cases:observability/createConfiguration",
|
||||
"cases:observability/updateConfiguration",
|
||||
]
|
||||
`;
|
||||
|
||||
|
@ -24,7 +24,6 @@ exports[`cases feature_privilege_builder within feature grants create privileges
|
|||
Array [
|
||||
"cases:securitySolution/createCase",
|
||||
"cases:securitySolution/createComment",
|
||||
"cases:securitySolution/createConfiguration",
|
||||
]
|
||||
`;
|
||||
|
||||
|
@ -52,10 +51,16 @@ Array [
|
|||
]
|
||||
`;
|
||||
|
||||
exports[`cases feature_privilege_builder within feature grants settings privileges under feature with id observability 1`] = `
|
||||
Array [
|
||||
"cases:observability/createConfiguration",
|
||||
"cases:observability/updateConfiguration",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cases feature_privilege_builder within feature grants update privileges under feature with id observability 1`] = `
|
||||
Array [
|
||||
"cases:observability/updateCase",
|
||||
"cases:observability/updateComment",
|
||||
"cases:observability/updateConfiguration",
|
||||
]
|
||||
`;
|
||||
|
|
|
@ -47,6 +47,7 @@ describe(`cases`, () => {
|
|||
['read', 'observability'],
|
||||
['update', 'observability'],
|
||||
['delete', 'securitySolution'],
|
||||
['settings', 'observability'],
|
||||
])('grants %s privileges under feature with id %s', (operation, featureID) => {
|
||||
const actions = new Actions();
|
||||
const casesFeaturePrivilege = new FeaturePrivilegeCasesBuilder(actions);
|
||||
|
@ -55,7 +56,6 @@ describe(`cases`, () => {
|
|||
cases: {
|
||||
[operation]: [featureID],
|
||||
},
|
||||
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
|
@ -88,8 +88,8 @@ describe(`cases`, () => {
|
|||
update: ['obs'],
|
||||
delete: ['security'],
|
||||
read: ['obs'],
|
||||
settings: ['security'],
|
||||
},
|
||||
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
|
@ -113,7 +113,6 @@ describe(`cases`, () => {
|
|||
"cases:security/pushCase",
|
||||
"cases:security/createCase",
|
||||
"cases:security/createComment",
|
||||
"cases:security/createConfiguration",
|
||||
"cases:security/getCase",
|
||||
"cases:security/getComment",
|
||||
"cases:security/getTags",
|
||||
|
@ -122,9 +121,10 @@ describe(`cases`, () => {
|
|||
"cases:security/findConfigurations",
|
||||
"cases:security/updateCase",
|
||||
"cases:security/updateComment",
|
||||
"cases:security/updateConfiguration",
|
||||
"cases:security/deleteCase",
|
||||
"cases:security/deleteComment",
|
||||
"cases:security/createConfiguration",
|
||||
"cases:security/updateConfiguration",
|
||||
"cases:obs/getCase",
|
||||
"cases:obs/getComment",
|
||||
"cases:obs/getTags",
|
||||
|
@ -133,7 +133,6 @@ describe(`cases`, () => {
|
|||
"cases:obs/findConfigurations",
|
||||
"cases:obs/updateCase",
|
||||
"cases:obs/updateComment",
|
||||
"cases:obs/updateConfiguration",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
@ -147,7 +146,6 @@ describe(`cases`, () => {
|
|||
all: ['security', 'other-security'],
|
||||
read: ['obs', 'other-obs'],
|
||||
},
|
||||
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
|
@ -171,7 +169,6 @@ describe(`cases`, () => {
|
|||
"cases:security/pushCase",
|
||||
"cases:security/createCase",
|
||||
"cases:security/createComment",
|
||||
"cases:security/createConfiguration",
|
||||
"cases:security/getCase",
|
||||
"cases:security/getComment",
|
||||
"cases:security/getTags",
|
||||
|
@ -180,13 +177,13 @@ describe(`cases`, () => {
|
|||
"cases:security/findConfigurations",
|
||||
"cases:security/updateCase",
|
||||
"cases:security/updateComment",
|
||||
"cases:security/updateConfiguration",
|
||||
"cases:security/deleteCase",
|
||||
"cases:security/deleteComment",
|
||||
"cases:security/createConfiguration",
|
||||
"cases:security/updateConfiguration",
|
||||
"cases:other-security/pushCase",
|
||||
"cases:other-security/createCase",
|
||||
"cases:other-security/createComment",
|
||||
"cases:other-security/createConfiguration",
|
||||
"cases:other-security/getCase",
|
||||
"cases:other-security/getComment",
|
||||
"cases:other-security/getTags",
|
||||
|
@ -195,9 +192,10 @@ describe(`cases`, () => {
|
|||
"cases:other-security/findConfigurations",
|
||||
"cases:other-security/updateCase",
|
||||
"cases:other-security/updateComment",
|
||||
"cases:other-security/updateConfiguration",
|
||||
"cases:other-security/deleteCase",
|
||||
"cases:other-security/deleteComment",
|
||||
"cases:other-security/createConfiguration",
|
||||
"cases:other-security/updateConfiguration",
|
||||
"cases:obs/getCase",
|
||||
"cases:obs/getComment",
|
||||
"cases:obs/getTags",
|
||||
|
|
|
@ -13,11 +13,16 @@ import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder';
|
|||
|
||||
export type CasesSupportedOperations = typeof allOperations[number];
|
||||
|
||||
// if you add a value here you'll likely also need to make changes here:
|
||||
// x-pack/plugins/cases/server/authorization/index.ts
|
||||
/**
|
||||
* If you add a new operation type (all, push, update, etc) you should also
|
||||
* extend the mapping here x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts
|
||||
*
|
||||
* Also if you add a new operation (createCase, updateCase, etc) here you'll likely also need to make changes here:
|
||||
* x-pack/plugins/cases/server/authorization/index.ts
|
||||
*/
|
||||
|
||||
const pushOperations = ['pushCase'] as const;
|
||||
const createOperations = ['createCase', 'createComment', 'createConfiguration'] as const;
|
||||
const createOperations = ['createCase', 'createComment'] as const;
|
||||
const readOperations = [
|
||||
'getCase',
|
||||
'getComment',
|
||||
|
@ -26,14 +31,16 @@ const readOperations = [
|
|||
'getUserActions',
|
||||
'findConfigurations',
|
||||
] as const;
|
||||
const updateOperations = ['updateCase', 'updateComment', 'updateConfiguration'] as const;
|
||||
const updateOperations = ['updateCase', 'updateComment'] as const;
|
||||
const deleteOperations = ['deleteCase', 'deleteComment'] as const;
|
||||
const settingsOperations = ['createConfiguration', 'updateConfiguration'] as const;
|
||||
const allOperations = [
|
||||
...pushOperations,
|
||||
...createOperations,
|
||||
...readOperations,
|
||||
...updateOperations,
|
||||
...deleteOperations,
|
||||
...settingsOperations,
|
||||
] as const;
|
||||
|
||||
export class FeaturePrivilegeCasesBuilder extends BaseFeaturePrivilegeBuilder {
|
||||
|
@ -57,6 +64,7 @@ export class FeaturePrivilegeCasesBuilder extends BaseFeaturePrivilegeBuilder {
|
|||
...getCasesPrivilege(readOperations, privilegeDefinition.cases?.read),
|
||||
...getCasesPrivilege(updateOperations, privilegeDefinition.cases?.update),
|
||||
...getCasesPrivilege(deleteOperations, privilegeDefinition.cases?.delete),
|
||||
...getCasesPrivilege(settingsOperations, privilegeDefinition.cases?.settings),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import type { AppLeaveHandler } from '@kbn/core/public';
|
|||
|
||||
import { APP_ID } from '../../common/constants';
|
||||
import { RouteCapture } from '../common/components/endpoint/route_capture';
|
||||
import { useGetUserCasesPermissions, useKibana } from '../common/lib/kibana';
|
||||
import { useKibana } from '../common/lib/kibana';
|
||||
import type { AppAction } from '../common/store/actions';
|
||||
import { ManageRoutesSpy } from '../common/utils/route/manage_spy_routes';
|
||||
import { NotFoundPage } from './404';
|
||||
|
@ -29,7 +29,7 @@ interface RouterProps {
|
|||
const PageRouterComponent: FC<RouterProps> = ({ children, history, onAppLeave }) => {
|
||||
const { cases } = useKibana().services;
|
||||
const CasesContext = cases.ui.getCasesContext();
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
const dispatch = useDispatch<(action: AppAction) => void>();
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import {
|
||||
CREATE_CASES_CAPABILITY,
|
||||
READ_CASES_CAPABILITY,
|
||||
UPDATE_CASES_CAPABILITY,
|
||||
CASES_SETTINGS_CAPABILITY,
|
||||
} from '@kbn/cases-plugin/common';
|
||||
import { getCasesDeepLinks } from '@kbn/cases-plugin/public';
|
||||
import { CASES_FEATURE_ID, CASES_PATH, SecurityPageName } from '../../common/constants';
|
||||
|
@ -22,7 +22,7 @@ const casesLinks = getCasesDeepLinks<LinkItem>({
|
|||
capabilities: [`${CASES_FEATURE_ID}.${READ_CASES_CAPABILITY}`],
|
||||
},
|
||||
[SecurityPageName.caseConfigure]: {
|
||||
capabilities: [`${CASES_FEATURE_ID}.${UPDATE_CASES_CAPABILITY}`],
|
||||
capabilities: [`${CASES_FEATURE_ID}.${CASES_SETTINGS_CAPABILITY}`],
|
||||
sideNavDisabled: true,
|
||||
},
|
||||
[SecurityPageName.caseCreate]: {
|
||||
|
|
|
@ -21,7 +21,7 @@ import { TimelineId } from '../../../common/types/timeline';
|
|||
|
||||
import { getRuleDetailsUrl, useFormatUrl } from '../../common/components/link_to';
|
||||
|
||||
import { useGetUserCasesPermissions, useKibana, useNavigation } from '../../common/lib/kibana';
|
||||
import { useKibana, useNavigation } from '../../common/lib/kibana';
|
||||
import {
|
||||
APP_ID,
|
||||
CASES_PATH,
|
||||
|
@ -56,7 +56,7 @@ const TimelineDetailsPanel = () => {
|
|||
const CaseContainerComponent: React.FC = () => {
|
||||
const { cases } = useKibana().services;
|
||||
const { getAppUrl, navigateTo } = useNavigation();
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
const dispatch = useDispatch();
|
||||
const { formatUrl: detectionsFormatUrl, search: detectionsUrlSearch } = useFormatUrl(
|
||||
SecurityPageName.rules
|
||||
|
|
|
@ -5,34 +5,39 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export const noCasesCapabilities = () => ({
|
||||
import type { CasesPermissions, CasesCapabilities } from '@kbn/cases-plugin/common';
|
||||
|
||||
export const noCasesCapabilities = (): CasesCapabilities => ({
|
||||
create_cases: false,
|
||||
read_cases: false,
|
||||
update_cases: false,
|
||||
delete_cases: false,
|
||||
push_cases: false,
|
||||
cases_connector: false,
|
||||
cases_connectors: false,
|
||||
cases_settings: false,
|
||||
});
|
||||
|
||||
export const readCasesCapabilities = () => ({
|
||||
export const readCasesCapabilities = (): CasesCapabilities => ({
|
||||
create_cases: false,
|
||||
read_cases: true,
|
||||
update_cases: false,
|
||||
delete_cases: false,
|
||||
push_cases: false,
|
||||
cases_connector: true,
|
||||
cases_connectors: true,
|
||||
cases_settings: false,
|
||||
});
|
||||
|
||||
export const allCasesCapabilities = () => ({
|
||||
export const allCasesCapabilities = (): CasesCapabilities => ({
|
||||
create_cases: true,
|
||||
read_cases: true,
|
||||
update_cases: true,
|
||||
delete_cases: true,
|
||||
push_cases: true,
|
||||
cases_connector: true,
|
||||
cases_connectors: true,
|
||||
cases_settings: true,
|
||||
});
|
||||
|
||||
export const noCasesPermissions = () => ({
|
||||
export const noCasesPermissions = (): CasesPermissions => ({
|
||||
all: false,
|
||||
create: false,
|
||||
read: false,
|
||||
|
@ -40,9 +45,10 @@ export const noCasesPermissions = () => ({
|
|||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
settings: false,
|
||||
});
|
||||
|
||||
export const readCasesPermissions = () => ({
|
||||
export const readCasesPermissions = (): CasesPermissions => ({
|
||||
all: false,
|
||||
create: false,
|
||||
read: true,
|
||||
|
@ -50,9 +56,10 @@ export const readCasesPermissions = () => ({
|
|||
delete: false,
|
||||
push: false,
|
||||
connectors: true,
|
||||
settings: false,
|
||||
});
|
||||
|
||||
export const writeCasesPermissions = () => ({
|
||||
export const writeCasesPermissions = (): CasesPermissions => ({
|
||||
all: false,
|
||||
create: true,
|
||||
read: false,
|
||||
|
@ -60,9 +67,10 @@ export const writeCasesPermissions = () => ({
|
|||
delete: true,
|
||||
push: true,
|
||||
connectors: true,
|
||||
settings: true,
|
||||
});
|
||||
|
||||
export const allCasesPermissions = () => ({
|
||||
export const allCasesPermissions = (): CasesPermissions => ({
|
||||
all: true,
|
||||
create: true,
|
||||
read: true,
|
||||
|
@ -70,4 +78,5 @@ export const allCasesPermissions = () => ({
|
|||
delete: true,
|
||||
push: true,
|
||||
connectors: true,
|
||||
settings: true,
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@ import { mockAlertDetailsData } from './__mocks__';
|
|||
import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy';
|
||||
import { TimelineTabs } from '../../../../common/types/timeline';
|
||||
import { useInvestigationTimeEnrichment } from '../../containers/cti/event_enrichment';
|
||||
import { useGetUserCasesPermissions, useKibana } from '../../lib/kibana';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features';
|
||||
|
||||
|
@ -44,14 +44,8 @@ jest.mock('../../../timelines/components/timeline/body/renderers', () => {
|
|||
});
|
||||
|
||||
jest.mock('../../lib/kibana');
|
||||
const originalKibanaLib = jest.requireActual('../../lib/kibana');
|
||||
const useKibanaMock = useKibana as jest.Mocked<typeof useKibana>;
|
||||
|
||||
// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object
|
||||
// The returned permissions object will indicate that the user does not have permissions by default
|
||||
const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock;
|
||||
mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions);
|
||||
|
||||
jest.mock('../../containers/cti/event_enrichment');
|
||||
|
||||
jest.mock('../../../detection_engine/rule_management/logic/use_rule_with_fallback', () => {
|
||||
|
|
|
@ -12,7 +12,6 @@ import { TestProviders } from '../../../mock';
|
|||
|
||||
import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline';
|
||||
import { useKibana as mockUseKibana } from '../../../lib/kibana/__mocks__';
|
||||
import { useGetUserCasesPermissions } from '../../../lib/kibana';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features';
|
||||
import { licenseService } from '../../../hooks/use_license';
|
||||
import { noCasesPermissions, readCasesPermissions } from '../../../../cases_test_utils';
|
||||
|
@ -20,12 +19,13 @@ import { Insights } from './insights';
|
|||
import * as i18n from './translations';
|
||||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
const mockCanUseCases = jest.fn();
|
||||
|
||||
jest.mock('../../../lib/kibana', () => {
|
||||
const original = jest.requireActual('../../../lib/kibana');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useGetUserCasesPermissions: jest.fn(),
|
||||
useToasts: jest.fn().mockReturnValue({ addWarning: jest.fn() }),
|
||||
useKibana: () => ({
|
||||
...mockedUseKibana,
|
||||
|
@ -35,12 +35,12 @@ jest.mock('../../../lib/kibana', () => {
|
|||
api: {
|
||||
getRelatedCases: jest.fn(),
|
||||
},
|
||||
helpers: { canUseCases: mockCanUseCases },
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock;
|
||||
|
||||
jest.mock('../../../hooks/use_license', () => {
|
||||
const licenseServiceInstance = {
|
||||
|
@ -94,7 +94,7 @@ const data: TimelineEventsDetailsItem[] = [
|
|||
|
||||
describe('Insights', () => {
|
||||
beforeEach(() => {
|
||||
mockUseGetUserCasesPermissions.mockReturnValue(noCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(noCasesPermissions());
|
||||
});
|
||||
|
||||
it('does not render when there is no content to show', () => {
|
||||
|
@ -116,7 +116,7 @@ describe('Insights', () => {
|
|||
// It will show for all users that are able to read case data.
|
||||
// Enabling that permission, will show the case insight module which
|
||||
// is necessary to pass this test.
|
||||
mockUseGetUserCasesPermissions.mockReturnValue(readCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(readCasesPermissions());
|
||||
|
||||
render(
|
||||
<TestProviders>
|
||||
|
|
|
@ -11,12 +11,12 @@ import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
|||
import { ALERT_SUPPRESSION_DOCS_COUNT } from '@kbn/rule-data-utils';
|
||||
import { find } from 'lodash/fp';
|
||||
|
||||
import { APP_ID } from '../../../../../common';
|
||||
import * as i18n from './translations';
|
||||
|
||||
import type { BrowserFields } from '../../../containers/source';
|
||||
import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline';
|
||||
import { hasData } from './helpers';
|
||||
import { useGetUserCasesPermissions } from '../../../lib/kibana';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features';
|
||||
import { useLicense } from '../../../hooks/use_license';
|
||||
import { RelatedAlertsByProcessAncestry } from './related_alerts_by_process_ancestry';
|
||||
|
@ -24,6 +24,7 @@ import { RelatedCases } from './related_cases';
|
|||
import { RelatedAlertsBySourceEvent } from './related_alerts_by_source_event';
|
||||
import { RelatedAlertsBySession } from './related_alerts_by_session';
|
||||
import { RelatedAlertsUpsell } from './related_alerts_upsell';
|
||||
import { useKibana } from '../../../lib/kibana';
|
||||
|
||||
const StyledInsightItem = euiStyled(EuiFlexItem)`
|
||||
border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
|
@ -45,6 +46,7 @@ interface Props {
|
|||
*/
|
||||
export const Insights = React.memo<Props>(
|
||||
({ browserFields, eventId, data, isReadOnly, scopeId }) => {
|
||||
const { cases } = useKibana().services;
|
||||
const isRelatedAlertsByProcessAncestryEnabled = useIsExperimentalFeatureEnabled(
|
||||
'insightsRelatedAlertsByProcessAncestry'
|
||||
);
|
||||
|
@ -83,7 +85,7 @@ export const Insights = React.memo<Props>(
|
|||
);
|
||||
const hasAlertSuppressionField = hasData(alertSuppressionField);
|
||||
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
const hasCasesReadPermissions = userCasesPermissions.read;
|
||||
|
||||
// Make sure that the alert has at least one of the associated fields
|
||||
|
|
|
@ -10,7 +10,6 @@ import React from 'react';
|
|||
|
||||
import { TestProviders } from '../../../mock';
|
||||
import { useKibana as mockUseKibana } from '../../../lib/kibana/__mocks__';
|
||||
import { useGetUserCasesPermissions } from '../../../lib/kibana';
|
||||
import { RelatedCases } from './related_cases';
|
||||
import { noCasesPermissions, readCasesPermissions } from '../../../../cases_test_utils';
|
||||
import { CASES_LOADING, CASES_COUNT } from './translations';
|
||||
|
@ -19,13 +18,14 @@ import { AlertsCasesTourSteps } from '../../guided_onboarding_tour/tour_config';
|
|||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
const mockGetRelatedCases = jest.fn();
|
||||
const mockCanUseCases = jest.fn();
|
||||
|
||||
jest.mock('../../guided_onboarding_tour');
|
||||
jest.mock('../../../lib/kibana', () => {
|
||||
const original = jest.requireActual('../../../lib/kibana');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useGetUserCasesPermissions: jest.fn(),
|
||||
useToasts: jest.fn().mockReturnValue({ addWarning: jest.fn() }),
|
||||
useKibana: () => ({
|
||||
...mockedUseKibana,
|
||||
|
@ -35,6 +35,7 @@ jest.mock('../../../lib/kibana', () => {
|
|||
api: {
|
||||
getRelatedCases: mockGetRelatedCases,
|
||||
},
|
||||
helpers: { canUseCases: mockCanUseCases },
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
@ -47,7 +48,7 @@ window.HTMLElement.prototype.scrollIntoView = scrollToMock;
|
|||
|
||||
describe('Related Cases', () => {
|
||||
beforeEach(() => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(readCasesPermissions());
|
||||
(useTourContext as jest.Mock).mockReturnValue({
|
||||
activeStep: AlertsCasesTourSteps.viewCase,
|
||||
incrementStep: () => null,
|
||||
|
@ -58,7 +59,7 @@ describe('Related Cases', () => {
|
|||
});
|
||||
describe('When user does not have cases read permissions', () => {
|
||||
beforeEach(() => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(noCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(noCasesPermissions());
|
||||
});
|
||||
test('should not show related cases when user does not have permissions', async () => {
|
||||
await act(async () => {
|
||||
|
|
|
@ -22,7 +22,6 @@ import { useTimelineEvents } from './use_timelines_events';
|
|||
import { getDefaultControlColumn } from '../../../timelines/components/timeline/body/control_columns';
|
||||
import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers';
|
||||
import type { UseFieldBrowserOptionsProps } from '../../../timelines/components/fields_browser';
|
||||
import { useGetUserCasesPermissions } from '../../lib/kibana';
|
||||
import { TableId } from '@kbn/securitysolution-data-table';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
|
@ -38,13 +37,6 @@ jest.mock('react-redux', () => {
|
|||
};
|
||||
});
|
||||
|
||||
const originalKibanaLib = jest.requireActual('../../lib/kibana');
|
||||
|
||||
// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object
|
||||
// The returned permissions object will indicate that the user does not have permissions by default
|
||||
const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock;
|
||||
mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions);
|
||||
|
||||
jest.mock('./use_timelines_events');
|
||||
|
||||
jest.mock('../../utils/normalize_time_range');
|
||||
|
|
|
@ -11,21 +11,12 @@ import { TestProviders } from '../../mock';
|
|||
import { TEST_ID, SessionsView, defaultSessionsFilter } from '.';
|
||||
import type { EntityType } from '@kbn/timelines-plugin/common';
|
||||
import type { SessionsComponentsProps } from './types';
|
||||
import { useGetUserCasesPermissions } from '../../lib/kibana';
|
||||
import { TableId } from '@kbn/securitysolution-data-table';
|
||||
import { licenseService } from '../../hooks/use_license';
|
||||
import { mount } from 'enzyme';
|
||||
import type { EventsViewerProps } from '../events_viewer';
|
||||
|
||||
jest.mock('../../lib/kibana');
|
||||
|
||||
const originalKibanaLib = jest.requireActual('../../lib/kibana');
|
||||
|
||||
// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object
|
||||
// The returned permissions object will indicate that the user does not have permissions by default
|
||||
const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock;
|
||||
mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions);
|
||||
|
||||
jest.mock('../../utils/normalize_time_range');
|
||||
|
||||
const startDate = '2022-03-22T22:10:56.794Z';
|
||||
|
|
|
@ -101,6 +101,7 @@ describe('VisualizationActions', () => {
|
|||
.fn()
|
||||
.mockReturnValue({ open: mockGetCreateCaseFlyoutOpen }),
|
||||
},
|
||||
helpers: { canUseCases: jest.fn().mockReturnValue(allCasesPermissions()) },
|
||||
},
|
||||
application: {
|
||||
capabilities: { [CASES_FEATURE_ID]: allCasesCapabilities() },
|
||||
|
|
|
@ -8,7 +8,6 @@ import { renderHook } from '@testing-library/react-hooks';
|
|||
import { useKibana as mockUseKibana } from '../../lib/kibana/__mocks__';
|
||||
import { kpiHostMetricLensAttributes } from './lens_attributes/hosts/kpi_host_metric';
|
||||
import { useAddToExistingCase } from './use_add_to_existing_case';
|
||||
import { useGetUserCasesPermissions } from '../../lib/kibana';
|
||||
import {
|
||||
allCasesPermissions,
|
||||
readCasesPermissions,
|
||||
|
@ -18,13 +17,13 @@ import { AttachmentType } from '@kbn/cases-plugin/common';
|
|||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
const mockGetUseCasesAddToExistingCaseModal = jest.fn();
|
||||
const mockCanUseCases = jest.fn();
|
||||
|
||||
jest.mock('../../lib/kibana', () => {
|
||||
const original = jest.requireActual('../../lib/kibana');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useGetUserCasesPermissions: jest.fn(),
|
||||
useKibana: () => ({
|
||||
...mockedUseKibana,
|
||||
services: {
|
||||
|
@ -33,6 +32,7 @@ jest.mock('../../lib/kibana', () => {
|
|||
hooks: {
|
||||
useCasesAddToExistingCaseModal: mockGetUseCasesAddToExistingCaseModal,
|
||||
},
|
||||
helpers: { canUseCases: mockCanUseCases },
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
@ -47,7 +47,7 @@ describe('useAddToExistingCase', () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(allCasesPermissions());
|
||||
});
|
||||
|
||||
it('useCasesAddToExistingCaseModal with attachments', () => {
|
||||
|
@ -68,7 +68,7 @@ describe('useAddToExistingCase', () => {
|
|||
});
|
||||
|
||||
it("disables the button if the user can't create but can read", () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(readCasesPermissions());
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useAddToExistingCase({
|
||||
|
@ -81,7 +81,7 @@ describe('useAddToExistingCase', () => {
|
|||
});
|
||||
|
||||
it("disables the button if the user can't read but can create", () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(writeCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(writeCasesPermissions());
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useAddToExistingCase({
|
||||
|
|
|
@ -8,7 +8,8 @@ import { useCallback, useMemo } from 'react';
|
|||
import { AttachmentType, LENS_ATTACHMENT_TYPE } from '@kbn/cases-plugin/common';
|
||||
import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
|
||||
|
||||
import { useKibana, useGetUserCasesPermissions } from '../../lib/kibana';
|
||||
import { APP_ID } from '../../../../common';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
import { ADD_TO_CASE_SUCCESS } from './translations';
|
||||
import type { LensAttributes } from './types';
|
||||
|
||||
|
@ -21,8 +22,8 @@ export const useAddToExistingCase = ({
|
|||
lensAttributes: LensAttributes | null;
|
||||
timeRange: { from: string; to: string } | null;
|
||||
}) => {
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const { cases } = useKibana().services;
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
const attachments = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,6 @@ import { renderHook } from '@testing-library/react-hooks';
|
|||
import { useKibana as mockUseKibana } from '../../lib/kibana/__mocks__';
|
||||
import { kpiHostMetricLensAttributes } from './lens_attributes/hosts/kpi_host_metric';
|
||||
import { useAddToNewCase } from './use_add_to_new_case';
|
||||
import { useGetUserCasesPermissions } from '../../lib/kibana';
|
||||
import {
|
||||
allCasesPermissions,
|
||||
readCasesPermissions,
|
||||
|
@ -20,13 +19,13 @@ jest.mock('../../lib/kibana/kibana_react');
|
|||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
const mockGetUseCasesAddToNewCaseFlyout = jest.fn();
|
||||
const mockCanUseCases = jest.fn();
|
||||
|
||||
jest.mock('../../lib/kibana', () => {
|
||||
const original = jest.requireActual('../../lib/kibana');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useGetUserCasesPermissions: jest.fn(),
|
||||
useKibana: () => ({
|
||||
...mockedUseKibana,
|
||||
services: {
|
||||
|
@ -35,6 +34,7 @@ jest.mock('../../lib/kibana', () => {
|
|||
hooks: {
|
||||
useCasesAddToNewCaseFlyout: mockGetUseCasesAddToNewCaseFlyout,
|
||||
},
|
||||
helpers: { canUseCases: mockCanUseCases },
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
@ -47,7 +47,7 @@ describe('useAddToNewCase', () => {
|
|||
to: '2022-03-07T15:59:59.999Z',
|
||||
};
|
||||
beforeEach(() => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(allCasesPermissions());
|
||||
});
|
||||
|
||||
it('useCasesAddToNewCaseFlyout with attachments', () => {
|
||||
|
@ -64,7 +64,7 @@ describe('useAddToNewCase', () => {
|
|||
});
|
||||
|
||||
it("disables the button if the user can't create but can read", () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(readCasesPermissions());
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useAddToNewCase({
|
||||
|
@ -76,7 +76,7 @@ describe('useAddToNewCase', () => {
|
|||
});
|
||||
|
||||
it("disables the button if the user can't read but can create", () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(writeCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(writeCasesPermissions());
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useAddToNewCase({
|
||||
|
|
|
@ -8,7 +8,8 @@ import { useCallback, useMemo } from 'react';
|
|||
import { AttachmentType, LENS_ATTACHMENT_TYPE } from '@kbn/cases-plugin/common';
|
||||
import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
|
||||
|
||||
import { useKibana, useGetUserCasesPermissions } from '../../lib/kibana';
|
||||
import { APP_ID } from '../../../../common';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
import { ADD_TO_CASE_SUCCESS } from './translations';
|
||||
|
||||
import type { LensAttributes } from './types';
|
||||
|
@ -20,8 +21,9 @@ export interface UseAddToNewCaseProps {
|
|||
}
|
||||
|
||||
export const useAddToNewCase = ({ onClick, timeRange, lensAttributes }: UseAddToNewCaseProps) => {
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const { cases } = useKibana().services;
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
|
||||
const attachments = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
|
|
|
@ -95,7 +95,6 @@ export const useToasts = jest
|
|||
export const useCurrentUser = jest.fn();
|
||||
export const withKibana = jest.fn(createWithKibanaMock());
|
||||
export const KibanaContextProvider = jest.fn(createKibanaContextProviderMock());
|
||||
export const useGetUserCasesPermissions = jest.fn();
|
||||
export const useAppUrl = jest.fn().mockReturnValue({
|
||||
getAppUrl: jest
|
||||
.fn()
|
||||
|
|
|
@ -14,7 +14,6 @@ import { camelCase, isArray, isObject } from 'lodash';
|
|||
import { set } from '@kbn/safer-lodash-set';
|
||||
import type { AuthenticatedUser } from '@kbn/security-plugin/common';
|
||||
import type { Capabilities } from '@kbn/core/public';
|
||||
import type { CasesPermissions } from '@kbn/cases-plugin/common';
|
||||
import {
|
||||
useGetAppUrl,
|
||||
useNavigateTo,
|
||||
|
@ -22,11 +21,7 @@ import {
|
|||
type GetAppUrl,
|
||||
type NavigateTo,
|
||||
} from '@kbn/security-solution-navigation';
|
||||
import {
|
||||
CASES_FEATURE_ID,
|
||||
DEFAULT_DATE_FORMAT,
|
||||
DEFAULT_DATE_FORMAT_TZ,
|
||||
} from '../../../../common/constants';
|
||||
import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_FORMAT_TZ } from '../../../../common/constants';
|
||||
import { errorToToaster, useStateToaster } from '../../components/toasters';
|
||||
import type { StartServices } from '../../../types';
|
||||
import { useUiSetting, useKibana } from './kibana_react';
|
||||
|
@ -153,44 +148,6 @@ export const useCurrentUser = (): AuthenticatedElasticUser | null => {
|
|||
return user;
|
||||
};
|
||||
|
||||
export const useGetUserCasesPermissions = () => {
|
||||
const [casesPermissions, setCasesPermissions] = useState<CasesPermissions>({
|
||||
all: false,
|
||||
create: false,
|
||||
read: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
push: false,
|
||||
connectors: false,
|
||||
});
|
||||
const uiCapabilities = useKibana().services.application.capabilities;
|
||||
const casesCapabilities = useKibana().services.cases.helpers.getUICapabilities(
|
||||
uiCapabilities[CASES_FEATURE_ID]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setCasesPermissions({
|
||||
all: casesCapabilities.all,
|
||||
create: casesCapabilities.create,
|
||||
read: casesCapabilities.read,
|
||||
update: casesCapabilities.update,
|
||||
delete: casesCapabilities.delete,
|
||||
push: casesCapabilities.push,
|
||||
connectors: casesCapabilities.connectors,
|
||||
});
|
||||
}, [
|
||||
casesCapabilities.all,
|
||||
casesCapabilities.create,
|
||||
casesCapabilities.read,
|
||||
casesCapabilities.update,
|
||||
casesCapabilities.delete,
|
||||
casesCapabilities.push,
|
||||
casesCapabilities.connectors,
|
||||
]);
|
||||
|
||||
return casesPermissions;
|
||||
};
|
||||
|
||||
export const useAppUrl = useGetAppUrl;
|
||||
export { useNavigateTo, useNavigation };
|
||||
export type { GetAppUrl, NavigateTo };
|
||||
|
|
|
@ -117,7 +117,7 @@ export const createStartServicesMock = (
|
|||
const discover = discoverPluginMock.createStartContract();
|
||||
const cases = mockCasesContract();
|
||||
const dataViewServiceMock = dataViewPluginMocks.createStartContract();
|
||||
cases.helpers.getUICapabilities.mockReturnValue(noCasesPermissions());
|
||||
cases.helpers.canUseCases.mockReturnValue(noCasesPermissions());
|
||||
const triggersActionsUi = triggersActionsUiMock.createStart();
|
||||
const cloudExperiments = cloudExperimentsMock.createStartMock();
|
||||
const guidedOnboarding = guidedOnboardingMock.createStart();
|
||||
|
|
|
@ -74,17 +74,22 @@ jest.mock('../../../../common/lib/kibana', () => {
|
|||
application: {
|
||||
capabilities: { siem: { crud_alerts: true, read_alerts: true } },
|
||||
},
|
||||
cases: mockCasesContract(),
|
||||
cases: {
|
||||
...mockCasesContract(),
|
||||
helpers: {
|
||||
canUseCases: jest.fn().mockReturnValue({
|
||||
all: true,
|
||||
create: true,
|
||||
read: true,
|
||||
update: true,
|
||||
delete: true,
|
||||
push: true,
|
||||
}),
|
||||
getRuleIdFromEvent: jest.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
useGetUserCasesPermissions: jest.fn().mockReturnValue({
|
||||
all: true,
|
||||
create: true,
|
||||
read: true,
|
||||
update: true,
|
||||
delete: true,
|
||||
push: true,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import { render, screen } from '@testing-library/react';
|
|||
import userEvent from '@testing-library/user-event';
|
||||
import { useAddToCaseActions } from './use_add_to_case_actions';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import { useGetUserCasesPermissions, useKibana } from '../../../../common/lib/kibana';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { useTourContext } from '../../../../common/components/guided_onboarding_tour';
|
||||
import {
|
||||
AlertsCasesTourSteps,
|
||||
|
@ -20,6 +20,7 @@ import {
|
|||
} from '../../../../common/components/guided_onboarding_tour/tour_config';
|
||||
import { CasesTourSteps } from '../../../../common/components/guided_onboarding_tour/cases_tour_steps';
|
||||
import type { AlertTableContextMenuItem } from '../types';
|
||||
import { allCasesPermissions } from '../../../../cases_test_utils';
|
||||
|
||||
jest.mock('../../../../common/components/guided_onboarding_tour');
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
|
@ -76,15 +77,6 @@ describe('useAddToCaseActions', () => {
|
|||
isTourShown: () => false,
|
||||
});
|
||||
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue({
|
||||
all: true,
|
||||
create: true,
|
||||
read: true,
|
||||
update: true,
|
||||
delete: true,
|
||||
push: true,
|
||||
});
|
||||
|
||||
useKibanaMock.mockReturnValue({
|
||||
services: {
|
||||
cases: {
|
||||
|
@ -94,6 +86,7 @@ describe('useAddToCaseActions', () => {
|
|||
},
|
||||
helpers: {
|
||||
getRuleIdFromEvent: () => null,
|
||||
canUseCases: jest.fn().mockReturnValue(allCasesPermissions()),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -9,6 +9,7 @@ import React, { useCallback, useMemo } from 'react';
|
|||
import { AttachmentType } from '@kbn/cases-plugin/common';
|
||||
import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
|
||||
import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs';
|
||||
import { APP_ID } from '../../../../../common';
|
||||
import { CasesTourSteps } from '../../../../common/components/guided_onboarding_tour/cases_tour_steps';
|
||||
import {
|
||||
AlertsCasesTourSteps,
|
||||
|
@ -16,7 +17,7 @@ import {
|
|||
SecurityStepId,
|
||||
} from '../../../../common/components/guided_onboarding_tour/tour_config';
|
||||
import { useTourContext } from '../../../../common/components/guided_onboarding_tour';
|
||||
import { useGetUserCasesPermissions, useKibana } from '../../../../common/lib/kibana';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import type { TimelineNonEcsData } from '../../../../../common/search_strategy';
|
||||
import { ADD_TO_EXISTING_CASE, ADD_TO_NEW_CASE } from '../translations';
|
||||
import type { AlertTableContextMenuItem } from '../types';
|
||||
|
@ -43,7 +44,7 @@ export const useAddToCaseActions = ({
|
|||
refetch,
|
||||
}: UseAddToCaseActions) => {
|
||||
const { cases: casesUi } = useKibana().services;
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const userCasesPermissions = casesUi.helpers.canUseCases([APP_ID]);
|
||||
|
||||
const isAlert = useMemo(() => {
|
||||
return ecsData?.event?.kind?.includes('signal');
|
||||
|
|
|
@ -23,7 +23,6 @@ import { usePreviewHistogram } from './use_preview_histogram';
|
|||
|
||||
import { PreviewHistogram } from './preview_histogram';
|
||||
import { ALL_VALUES_ZEROS_TITLE } from '../../../../common/components/charts/translation';
|
||||
import { useGetUserCasesPermissions } from '../../../../common/lib/kibana';
|
||||
import { useTimelineEvents } from '../../../../common/components/events_viewer/use_timelines_events';
|
||||
import { TableId } from '@kbn/securitysolution-data-table';
|
||||
import { createStore } from '../../../../common/store';
|
||||
|
@ -58,12 +57,7 @@ const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as j
|
|||
const getMockUseIsExperimentalFeatureEnabled =
|
||||
(mockMapping?: Partial<ExperimentalFeatures>) => (flag: keyof typeof allowedExperimentalValues) =>
|
||||
mockMapping ? mockMapping?.[flag] : allowedExperimentalValues?.[flag];
|
||||
const originalKibanaLib = jest.requireActual('../../../../common/lib/kibana');
|
||||
|
||||
// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object
|
||||
// The returned permissions object will indicate that the user does not have permissions by default
|
||||
const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock;
|
||||
mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions);
|
||||
const mockUseFieldBrowserOptions = jest.fn();
|
||||
jest.mock('../../../../timelines/components/fields_browser', () => ({
|
||||
useFieldBrowserOptions: (props: UseFieldBrowserOptionsProps) => mockUseFieldBrowserOptions(props),
|
||||
|
|
|
@ -18,7 +18,7 @@ import { TimelineId } from '../../../../common/types/timeline';
|
|||
import { TestProviders } from '../../../common/mock';
|
||||
import { mockTimelines } from '../../../common/mock/mock_timelines_plugin';
|
||||
import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react.mock';
|
||||
import { useKibana, useGetUserCasesPermissions, useHttp } from '../../../common/lib/kibana';
|
||||
import { useKibana, useHttp } from '../../../common/lib/kibana';
|
||||
import { mockCasesContract } from '@kbn/cases-plugin/public/mocks';
|
||||
import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '../../../common/components/user_privileges/user_privileges_context';
|
||||
import { useUserPrivileges } from '../../../common/components/user_privileges';
|
||||
|
@ -46,7 +46,6 @@ jest.mock('../user_info', () => ({
|
|||
}));
|
||||
|
||||
jest.mock('../../../common/lib/kibana');
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions());
|
||||
|
||||
jest.mock('../../containers/detection_engine/alerts/use_alerts_privileges', () => ({
|
||||
useAlertsPrivileges: jest.fn().mockReturnValue({ hasIndexWrite: true, hasKibanaCRUD: true }),
|
||||
|
@ -119,7 +118,13 @@ describe('take action dropdown', () => {
|
|||
services: {
|
||||
...mockStartServicesMock,
|
||||
timelines: { ...mockTimelines },
|
||||
cases: mockCasesContract(),
|
||||
cases: {
|
||||
...mockCasesContract(),
|
||||
helpers: {
|
||||
canUseCases: jest.fn().mockReturnValue(allCasesPermissions()),
|
||||
getRuleIdFromEvent: () => null,
|
||||
},
|
||||
},
|
||||
osquery: {
|
||||
isOsqueryAvailable: jest.fn().mockReturnValue(true),
|
||||
},
|
||||
|
|
|
@ -7,13 +7,32 @@
|
|||
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
|
||||
import { useGetUserCasesPermissions } from '../../../../common/lib/kibana';
|
||||
import { useKibana as mockUseKibana } from '../../../../common/lib/kibana/__mocks__';
|
||||
import { useShowRelatedCases } from './use_show_related_cases';
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
const mockCanUseCases = jest.fn();
|
||||
|
||||
jest.mock('../../../../common/lib/kibana/kibana_react', () => {
|
||||
const original = jest.requireActual('../../../../common/lib/kibana/kibana_react');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useKibana: () => ({
|
||||
...mockedUseKibana,
|
||||
services: {
|
||||
...mockedUseKibana.services,
|
||||
cases: {
|
||||
helpers: { canUseCases: mockCanUseCases },
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
describe('useShowRelatedCases', () => {
|
||||
it(`should return false if user doesn't have cases read privilege`, () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue({
|
||||
mockCanUseCases.mockReturnValue({
|
||||
all: false,
|
||||
create: false,
|
||||
read: false,
|
||||
|
@ -28,7 +47,7 @@ describe('useShowRelatedCases', () => {
|
|||
});
|
||||
|
||||
it('should return true if user has cases read privilege', () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue({
|
||||
mockCanUseCases.mockReturnValue({
|
||||
all: false,
|
||||
create: false,
|
||||
read: true,
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { useGetUserCasesPermissions } from '../../../../common/lib/kibana';
|
||||
import { APP_ID } from '../../../../../common';
|
||||
import { useKibana } from '../../../../common/lib/kibana/kibana_react';
|
||||
|
||||
/**
|
||||
* Returns true if the user has read privileges for cases, false otherwise
|
||||
*/
|
||||
export const useShowRelatedCases = (): boolean => {
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const { cases } = useKibana().services;
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
|
||||
return userCasesPermissions.read;
|
||||
};
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { useGetUserCasesPermissions, useKibana } from '../../../common/lib/kibana';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import { APP_ID } from '../../../../common/constants';
|
||||
|
||||
const MAX_CASES_TO_SHOW = 3;
|
||||
const RecentCasesComponent = () => {
|
||||
const { cases } = useKibana().services;
|
||||
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
|
||||
return cases.ui.getRecentCases({
|
||||
permissions: userCasesPermissions,
|
||||
|
|
|
@ -10,7 +10,7 @@ import { mount } from 'enzyme';
|
|||
import { waitFor } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { Sidebar } from './sidebar';
|
||||
import { useGetUserCasesPermissions, useKibana } from '../../../common/lib/kibana';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import type { CaseUiClientMock } from '@kbn/cases-plugin/public/mocks';
|
||||
import { casesPluginMock } from '@kbn/cases-plugin/public/mocks';
|
||||
import { noCasesPermissions, readCasesPermissions } from '../../../cases_test_utils';
|
||||
|
@ -38,7 +38,7 @@ describe('Sidebar', () => {
|
|||
});
|
||||
|
||||
it('does not render the recently created cases section when the user does not have read permissions', async () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(noCasesPermissions());
|
||||
casesMock.helpers.canUseCases.mockReturnValue(noCasesPermissions());
|
||||
|
||||
await waitFor(() =>
|
||||
mount(
|
||||
|
@ -52,7 +52,7 @@ describe('Sidebar', () => {
|
|||
});
|
||||
|
||||
it('does render the recently created cases section when the user has read permissions', async () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions());
|
||||
casesMock.helpers.canUseCases.mockReturnValue(readCasesPermissions());
|
||||
|
||||
await waitFor(() =>
|
||||
mount(
|
||||
|
|
|
@ -8,7 +8,12 @@
|
|||
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { ENABLE_NEWS_FEED_SETTING, NEWS_FEED_URL_SETTING } from '../../../../common/constants';
|
||||
import { useKibana } from '../../../common/lib/kibana/kibana_react';
|
||||
import {
|
||||
APP_ID,
|
||||
ENABLE_NEWS_FEED_SETTING,
|
||||
NEWS_FEED_URL_SETTING,
|
||||
} from '../../../../common/constants';
|
||||
import { Filters as RecentTimelinesFilters } from '../recent_timelines/filters';
|
||||
import { StatefulRecentTimelines } from '../recent_timelines';
|
||||
import { StatefulNewsFeed } from '../../../common/components/news_feed';
|
||||
|
@ -17,7 +22,6 @@ import { SidebarHeader } from '../../../common/components/sidebar_header';
|
|||
|
||||
import * as i18n from '../../pages/translations';
|
||||
import { RecentCases } from '../recent_cases';
|
||||
import { useGetUserCasesPermissions } from '../../../common/lib/kibana';
|
||||
|
||||
const SidebarSpacerComponent = () => (
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -30,6 +34,7 @@ export const Sidebar = React.memo<{
|
|||
recentTimelinesFilterBy: RecentTimelinesFilterMode;
|
||||
setRecentTimelinesFilterBy: (filterBy: RecentTimelinesFilterMode) => void;
|
||||
}>(({ recentTimelinesFilterBy, setRecentTimelinesFilterBy }) => {
|
||||
const { cases } = useKibana().services;
|
||||
const recentTimelinesFilters = useMemo(
|
||||
() => (
|
||||
<RecentTimelinesFilters
|
||||
|
@ -41,7 +46,8 @@ export const Sidebar = React.memo<{
|
|||
);
|
||||
|
||||
// only render the recently created cases view if the user has at least read permissions
|
||||
const hasCasesReadPermissions = useGetUserCasesPermissions().read;
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
const hasCasesReadPermissions = userCasesPermissions.read;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column" responsive={false} gutterSize="l">
|
||||
|
|
|
@ -30,14 +30,6 @@ jest.mock('../../common/lib/kibana', () => {
|
|||
return {
|
||||
...original,
|
||||
KibanaServices: mockKibanaServices,
|
||||
useGetUserCasesPermissions: () => ({
|
||||
all: false,
|
||||
create: false,
|
||||
read: true,
|
||||
update: false,
|
||||
delete: false,
|
||||
push: false,
|
||||
}),
|
||||
useKibana: jest.fn(),
|
||||
useUiSetting$: () => ['0,0.[000]'],
|
||||
};
|
||||
|
@ -80,6 +72,16 @@ describe('DataQuality', () => {
|
|||
hooks: {
|
||||
useCasesAddToNewCaseFlyout: jest.fn(),
|
||||
},
|
||||
helpers: {
|
||||
canUseCases: jest.fn().mockReturnValue({
|
||||
all: false,
|
||||
create: false,
|
||||
read: true,
|
||||
update: false,
|
||||
delete: false,
|
||||
push: false,
|
||||
}),
|
||||
},
|
||||
},
|
||||
configSettings: { ILMEnabled: true },
|
||||
},
|
||||
|
@ -307,6 +309,16 @@ describe('DataQuality', () => {
|
|||
hooks: {
|
||||
useCasesAddToNewCaseFlyout: jest.fn(),
|
||||
},
|
||||
helpers: {
|
||||
canUseCases: jest.fn().mockReturnValue({
|
||||
all: false,
|
||||
create: false,
|
||||
read: true,
|
||||
update: false,
|
||||
delete: false,
|
||||
push: false,
|
||||
}),
|
||||
},
|
||||
},
|
||||
configSettings: { ILMEnabled: false },
|
||||
},
|
||||
|
|
|
@ -38,15 +38,9 @@ import { HeaderPage } from '../../common/components/header_page';
|
|||
import { LandingPageComponent } from '../../common/components/landing_page';
|
||||
import { useLocalStorage } from '../../common/components/local_storage';
|
||||
import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper';
|
||||
import { DEFAULT_BYTES_FORMAT, DEFAULT_NUMBER_FORMAT } from '../../../common/constants';
|
||||
import { APP_ID, DEFAULT_BYTES_FORMAT, DEFAULT_NUMBER_FORMAT } from '../../../common/constants';
|
||||
import { useSourcererDataView } from '../../common/containers/sourcerer';
|
||||
import {
|
||||
KibanaServices,
|
||||
useGetUserCasesPermissions,
|
||||
useKibana,
|
||||
useToasts,
|
||||
useUiSetting$,
|
||||
} from '../../common/lib/kibana';
|
||||
import { KibanaServices, useKibana, useToasts, useUiSetting$ } from '../../common/lib/kibana';
|
||||
import { SpyRoute } from '../../common/utils/route/spy_routes';
|
||||
import { useSignalIndex } from '../../detections/containers/detection_engine/alerts/use_signal_index';
|
||||
import * as i18n from './translations';
|
||||
|
@ -141,9 +135,7 @@ const DataQualityComponent: React.FC = () => {
|
|||
const httpFetch = KibanaServices.get().http.fetch;
|
||||
const { baseTheme, theme } = useThemes();
|
||||
const toasts = useToasts();
|
||||
const {
|
||||
services: { telemetry },
|
||||
} = useKibana();
|
||||
|
||||
const addSuccessToast = useCallback(
|
||||
(toast: { title: string }) => {
|
||||
toasts.addSuccess(toast);
|
||||
|
@ -156,7 +148,7 @@ const DataQualityComponent: React.FC = () => {
|
|||
const [selectedOptions, setSelectedOptions] = useState<EuiComboBoxOptionOption[]>(defaultOptions);
|
||||
const { indicesExist, loading: isSourcererLoading, selectedPatterns } = useSourcererDataView();
|
||||
const { signalIndexName, loading: isSignalIndexNameLoading } = useSignalIndex();
|
||||
const { configSettings, cases } = useKibana().services;
|
||||
const { configSettings, cases, telemetry } = useKibana().services;
|
||||
const isILMAvailable = configSettings.ILMEnabled;
|
||||
|
||||
const [startDate, setStartTime] = useState<string>();
|
||||
|
@ -210,7 +202,7 @@ const DataQualityComponent: React.FC = () => {
|
|||
key: LOCAL_STORAGE_KEY,
|
||||
});
|
||||
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
const canUserCreateAndReadCases = useCallback(
|
||||
() => userCasesPermissions.create && userCasesPermissions.read,
|
||||
[userCasesPermissions.create, userCasesPermissions.read]
|
||||
|
|
|
@ -11,6 +11,7 @@ import { render } from '@testing-library/react';
|
|||
import { DetectionResponse } from './detection_response';
|
||||
import { TestProviders } from '../../common/mock';
|
||||
import { noCasesPermissions, readCasesPermissions } from '../../cases_test_utils';
|
||||
import { useKibana as mockUseKibana } from '../../common/lib/kibana/__mocks__';
|
||||
|
||||
jest.mock('../components/detection_response/alerts_by_status', () => ({
|
||||
AlertsByStatus: () => <div data-test-subj="mock_AlertsByStatus" />,
|
||||
|
@ -75,12 +76,24 @@ jest.mock('../../detections/containers/detection_engine/alerts/use_alerts_privil
|
|||
}));
|
||||
|
||||
const defaultUseCasesPermissionsReturn = readCasesPermissions();
|
||||
const mockUseCasesPermissions = jest.fn(() => defaultUseCasesPermissionsReturn);
|
||||
jest.mock('../../common/lib/kibana/hooks', () => {
|
||||
const original = jest.requireActual('../../common/lib/kibana/hooks');
|
||||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
const mockCanUseCases = jest.fn();
|
||||
|
||||
jest.mock('../../common/lib/kibana', () => {
|
||||
const original = jest.requireActual('../../common/lib/kibana');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useGetUserCasesPermissions: () => mockUseCasesPermissions(),
|
||||
useKibana: () => ({
|
||||
...mockedUseKibana,
|
||||
services: {
|
||||
...mockedUseKibana.services,
|
||||
cases: {
|
||||
helpers: { canUseCases: mockCanUseCases },
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -90,7 +103,7 @@ describe('DetectionResponse', () => {
|
|||
mockUseSourcererDataView.mockReturnValue(defaultUseSourcererReturn);
|
||||
mockUseAlertsPrivileges.mockReturnValue(defaultUseAlertsPrivilegesReturn);
|
||||
mockUseSignalIndex.mockReturnValue(defaultUseSignalIndexReturn);
|
||||
mockUseCasesPermissions.mockReturnValue(defaultUseCasesPermissionsReturn);
|
||||
mockCanUseCases.mockReturnValue(defaultUseCasesPermissionsReturn);
|
||||
});
|
||||
|
||||
it('should render default page', () => {
|
||||
|
@ -197,7 +210,7 @@ describe('DetectionResponse', () => {
|
|||
});
|
||||
|
||||
it('should not render cases data sections if the user does not have cases read permission', () => {
|
||||
mockUseCasesPermissions.mockReturnValue(noCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(noCasesPermissions());
|
||||
|
||||
const result = render(
|
||||
<TestProviders>
|
||||
|
@ -218,7 +231,7 @@ describe('DetectionResponse', () => {
|
|||
});
|
||||
|
||||
it('should render page permissions message if the user does not have read permission', () => {
|
||||
mockUseCasesPermissions.mockReturnValue(noCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(noCasesPermissions());
|
||||
mockUseAlertsPrivileges.mockReturnValue({
|
||||
hasKibanaREAD: true,
|
||||
hasIndexRead: false,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
|
||||
import type { DocLinks } from '@kbn/doc-links';
|
||||
import { APP_ID } from '../../../common';
|
||||
import { InputsModelId } from '../../common/store/inputs/constants';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features';
|
||||
import { SocTrends } from '../components/detection_response/soc_trends';
|
||||
|
@ -18,7 +19,6 @@ import { useSourcererDataView } from '../../common/containers/sourcerer';
|
|||
import { useSignalIndex } from '../../detections/containers/detection_engine/alerts/use_signal_index';
|
||||
import { useAlertsPrivileges } from '../../detections/containers/detection_engine/alerts/use_alerts_privileges';
|
||||
import { HeaderPage } from '../../common/components/header_page';
|
||||
import { useGetUserCasesPermissions } from '../../common/lib/kibana';
|
||||
|
||||
import { LandingPageComponent } from '../../common/components/landing_page';
|
||||
import { AlertsByStatus } from '../components/detection_response/alerts_by_status';
|
||||
|
@ -31,13 +31,16 @@ import { CasesByStatus } from '../components/detection_response/cases_by_status'
|
|||
import { NoPrivileges } from '../../common/components/no_privileges';
|
||||
import { FiltersGlobal } from '../../common/components/filters_global';
|
||||
import { useGlobalFilterQuery } from '../../common/hooks/use_global_filter_query';
|
||||
import { useKibana } from '../../common/lib/kibana';
|
||||
|
||||
const DetectionResponseComponent = () => {
|
||||
const { cases } = useKibana().services;
|
||||
const { filterQuery } = useGlobalFilterQuery();
|
||||
const { indicesExist, loading: isSourcererLoading, sourcererDataView } = useSourcererDataView();
|
||||
const { signalIndexName } = useSignalIndex();
|
||||
const { hasKibanaREAD, hasIndexRead } = useAlertsPrivileges();
|
||||
const canReadCases = useGetUserCasesPermissions().read;
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
const canReadCases = userCasesPermissions.read;
|
||||
const canReadAlerts = hasKibanaREAD && hasIndexRead;
|
||||
const isSocTrendsEnabled = useIsExperimentalFeatureEnabled('socTrendsEnabled');
|
||||
if (!canReadAlerts && !canReadCases) {
|
||||
|
|
|
@ -7,19 +7,46 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import { useKibana, useGetUserCasesPermissions } from '../../../../common/lib/kibana';
|
||||
import { TestProviders, mockIndexNames, mockIndexPattern } from '../../../../common/mock';
|
||||
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
|
||||
import { allCasesPermissions, readCasesPermissions } from '../../../../cases_test_utils';
|
||||
import { mockBrowserFields } from '../../../../common/containers/source/mock';
|
||||
import { TimelineActionMenu } from '.';
|
||||
import { TimelineId, TimelineTabs } from '../../../../../common/types';
|
||||
import { useKibana as mockUseKibana } from '../../../../common/lib/kibana/__mocks__';
|
||||
|
||||
const mockUseSourcererDataView: jest.Mock = useSourcererDataView as jest.Mock;
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
const mockCanUseCases = jest.fn();
|
||||
|
||||
jest.mock('../../../../common/containers/sourcerer');
|
||||
|
||||
const useKibanaMock = useKibana as jest.Mocked<typeof useKibana>;
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
jest.mock('../../../../common/lib/kibana/kibana_react', () => {
|
||||
const original = jest.requireActual('../../../../common/lib/kibana/kibana_react');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useKibana: () => ({
|
||||
...mockedUseKibana,
|
||||
services: {
|
||||
...mockedUseKibana.services,
|
||||
cases: {
|
||||
...mockedUseKibana.services.cases,
|
||||
helpers: { canUseCases: mockCanUseCases },
|
||||
},
|
||||
},
|
||||
application: {
|
||||
capabilities: {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
catalogue: {},
|
||||
actions: { show: true, crud: true },
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('@kbn/i18n-react', () => {
|
||||
const originalModule = jest.requireActual('@kbn/i18n-react');
|
||||
const FormattedRelative = jest.fn().mockImplementation(() => '20 hours ago');
|
||||
|
@ -41,20 +68,15 @@ describe('Action menu', () => {
|
|||
beforeEach(() => {
|
||||
// Mocking these services is required for the header component to render.
|
||||
mockUseSourcererDataView.mockImplementation(() => sourcererDefaultValue);
|
||||
useKibanaMock().services.application.capabilities = {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
catalogue: {},
|
||||
actions: { show: true, crud: true },
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('AddToCaseButton', () => {
|
||||
it('renders the button when the user has create and read permissions', () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(allCasesPermissions());
|
||||
|
||||
render(
|
||||
<TestProviders>
|
||||
|
@ -70,7 +92,7 @@ describe('Action menu', () => {
|
|||
});
|
||||
|
||||
it('does not render the button when the user does not have create permissions', () => {
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions());
|
||||
mockCanUseCases.mockReturnValue(readCasesPermissions());
|
||||
|
||||
render(
|
||||
<TestProviders>
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { useGetUserCasesPermissions } from '../../../../common/lib/kibana';
|
||||
import { useKibana } from '../../../../common/lib/kibana/kibana_react';
|
||||
import { APP_ID } from '../../../../../common';
|
||||
import type { TimelineTabs } from '../../../../../common/types';
|
||||
import { InspectButton } from '../../../../common/components/inspect';
|
||||
import { InputsModelId } from '../../../../common/store/inputs/constants';
|
||||
|
@ -29,7 +30,9 @@ const TimelineActionMenuComponent = ({
|
|||
activeTab,
|
||||
isInspectButtonDisabled,
|
||||
}: TimelineActionMenuProps) => {
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const { cases } = useKibana().services;
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
gutterSize="xs"
|
||||
|
|
|
@ -10,7 +10,7 @@ import { render, screen } from '@testing-library/react';
|
|||
import userEvent from '@testing-library/user-event';
|
||||
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
|
||||
|
||||
import { useKibana, useGetUserCasesPermissions } from '../../../../common/lib/kibana';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
|
||||
import { mockTimelineModel, TestProviders } from '../../../../common/mock';
|
||||
import { AddToCaseButton } from '.';
|
||||
|
@ -36,13 +36,6 @@ jest.mock('react-redux', () => {
|
|||
});
|
||||
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
const originalKibanaLib = jest.requireActual('../../../../common/lib/kibana');
|
||||
|
||||
// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object
|
||||
// The returned permissions object will indicate that the user does not have permissions by default
|
||||
const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock;
|
||||
mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions);
|
||||
|
||||
jest.mock('../../../../common/hooks/use_selector');
|
||||
|
||||
const useKibanaMock = useKibana as jest.Mocked<typeof useKibana>;
|
||||
|
|
|
@ -15,7 +15,7 @@ import { APP_ID, APP_UI_ID } from '../../../../../common/constants';
|
|||
import { timelineSelectors } from '../../../store/timeline';
|
||||
import { setInsertTimeline, showTimeline } from '../../../store/timeline/actions';
|
||||
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
|
||||
import { useGetUserCasesPermissions, useKibana } from '../../../../common/lib/kibana';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { TimelineId } from '../../../../../common/types/timeline';
|
||||
import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline';
|
||||
import { getCreateCaseUrl, getCaseDetailsUrl } from '../../../../common/components/link_to';
|
||||
|
@ -68,7 +68,7 @@ const AddToCaseButtonComponent: React.FC<Props> = ({ timelineId }) => {
|
|||
[dispatch, graphEventId, navigateToApp, savedObjectId, timelineId, timelineTitle]
|
||||
);
|
||||
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
|
||||
|
||||
const handleButtonClick = useCallback(() => {
|
||||
setPopover((currentIsOpen) => !currentIsOpen);
|
||||
|
|
|
@ -13,11 +13,7 @@ import { TimelineId } from '../../../../../../common/types/timeline';
|
|||
import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs';
|
||||
import { mockAlertDetailsData } from '../../../../../common/components/event_details/__mocks__';
|
||||
import type { TimelineEventsDetailsItem } from '../../../../../../common/search_strategy';
|
||||
import {
|
||||
KibanaServices,
|
||||
useGetUserCasesPermissions,
|
||||
useKibana,
|
||||
} from '../../../../../common/lib/kibana';
|
||||
import { KibanaServices, useKibana } from '../../../../../common/lib/kibana';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { mockCasesContract } from '@kbn/cases-plugin/public/mocks';
|
||||
|
||||
|
@ -70,12 +66,6 @@ jest.mock('../../../../../detections/components/user_info', () => ({
|
|||
}));
|
||||
|
||||
jest.mock('../../../../../common/lib/kibana');
|
||||
const originalKibanaLib = jest.requireActual('../../../../../common/lib/kibana');
|
||||
|
||||
// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object
|
||||
// The returned permissions object will indicate that the user does not have permissions by default
|
||||
const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock;
|
||||
mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions);
|
||||
|
||||
jest.mock(
|
||||
'../../../../../detections/containers/detection_engine/alerts/use_alerts_privileges',
|
||||
|
|
|
@ -11,11 +11,7 @@ import '../../../../common/mock/match_media';
|
|||
import { TestProviders } from '../../../../common/mock';
|
||||
import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline';
|
||||
import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs';
|
||||
import {
|
||||
KibanaServices,
|
||||
useKibana,
|
||||
useGetUserCasesPermissions,
|
||||
} from '../../../../common/lib/kibana';
|
||||
import { KibanaServices, useKibana } from '../../../../common/lib/kibana';
|
||||
import { mockBrowserFields, mockRuntimeMappings } from '../../../../common/containers/source/mock';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { mockCasesContext } from '@kbn/cases-plugin/public/mocks/mock_cases_context';
|
||||
|
@ -156,6 +152,9 @@ describe('event details panel component', () => {
|
|||
ui: {
|
||||
getCasesContext: () => mockCasesContext,
|
||||
},
|
||||
cases: {
|
||||
helpers: { canUseCases: jest.fn().mockReturnValue(allCasesPermissions()) },
|
||||
},
|
||||
},
|
||||
timelines: {
|
||||
getHoverActions: jest.fn().mockReturnValue({
|
||||
|
@ -168,11 +167,12 @@ describe('event details panel component', () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
(useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('it renders the take action dropdown in the timeline version', () => {
|
||||
const wrapper = render(
|
||||
<TestProviders>
|
||||
|
|
|
@ -32,7 +32,6 @@ import { defaultRowRenderers } from './body/renderers';
|
|||
import { useSourcererDataView } from '../../../common/containers/sourcerer';
|
||||
import { createStore } from '../../../common/store';
|
||||
import { SourcererScopeName } from '../../../common/store/sourcerer/model';
|
||||
import { useGetUserCasesPermissions } from '../../../common/lib/kibana';
|
||||
|
||||
jest.mock('../../containers', () => ({
|
||||
useTimelineEvents: jest.fn(),
|
||||
|
@ -43,12 +42,6 @@ jest.mock('./tabs_content', () => ({
|
|||
}));
|
||||
|
||||
jest.mock('../../../common/lib/kibana');
|
||||
const originalKibanaLib = jest.requireActual('../../../common/lib/kibana');
|
||||
|
||||
// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object
|
||||
// The returned permissions object will indicate that the user does not have permissions by default
|
||||
const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock;
|
||||
mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions);
|
||||
|
||||
jest.mock('../../../common/utils/normalize_time_range');
|
||||
jest.mock('@kbn/i18n-react', () => {
|
||||
|
|
|
@ -22,8 +22,22 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
savedObjectsTagging: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
canvas: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
maps: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
generalCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'],
|
||||
observabilityCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'],
|
||||
generalCases: [
|
||||
'all',
|
||||
'read',
|
||||
'minimal_all',
|
||||
'minimal_read',
|
||||
'cases_delete',
|
||||
'cases_settings',
|
||||
],
|
||||
observabilityCases: [
|
||||
'all',
|
||||
'read',
|
||||
'minimal_all',
|
||||
'minimal_read',
|
||||
'cases_delete',
|
||||
'cases_settings',
|
||||
],
|
||||
observabilityAIAssistant: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
slo: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
fleetv2: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
|
@ -57,7 +71,14 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
],
|
||||
uptime: ['all', 'read', 'minimal_all', 'minimal_read', 'elastic_managed_locations_enabled'],
|
||||
securitySolutionAssistant: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
securitySolutionCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'],
|
||||
securitySolutionCases: [
|
||||
'all',
|
||||
'read',
|
||||
'minimal_all',
|
||||
'minimal_read',
|
||||
'cases_delete',
|
||||
'cases_settings',
|
||||
],
|
||||
infrastructure: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
logs: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
apm: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
|
|
|
@ -98,8 +98,22 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
savedObjectsTagging: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
canvas: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
maps: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
generalCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'],
|
||||
observabilityCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'],
|
||||
generalCases: [
|
||||
'all',
|
||||
'read',
|
||||
'minimal_all',
|
||||
'minimal_read',
|
||||
'cases_delete',
|
||||
'cases_settings',
|
||||
],
|
||||
observabilityCases: [
|
||||
'all',
|
||||
'read',
|
||||
'minimal_all',
|
||||
'minimal_read',
|
||||
'cases_delete',
|
||||
'cases_settings',
|
||||
],
|
||||
observabilityAIAssistant: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
slo: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
fleetv2: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
|
@ -139,7 +153,14 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
'minimal_read',
|
||||
],
|
||||
securitySolutionAssistant: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
securitySolutionCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'],
|
||||
securitySolutionCases: [
|
||||
'all',
|
||||
'read',
|
||||
'minimal_all',
|
||||
'minimal_read',
|
||||
'cases_delete',
|
||||
'cases_settings',
|
||||
],
|
||||
infrastructure: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
logs: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
apm: ['all', 'read', 'minimal_all', 'minimal_read'],
|
||||
|
|
|
@ -68,13 +68,13 @@ export class FixturePlugin implements Plugin<void, void, FixtureSetupDeps, Fixtu
|
|||
},
|
||||
subFeatures: [
|
||||
{
|
||||
name: 'Custom privileges',
|
||||
name: 'Delete',
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [
|
||||
{
|
||||
name: 'Delete',
|
||||
name: 'Delete cases and comments',
|
||||
id: 'cases_delete',
|
||||
includeIn: 'all',
|
||||
cases: {
|
||||
|
@ -90,6 +90,29 @@ export class FixturePlugin implements Plugin<void, void, FixtureSetupDeps, Fixtu
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Case Settings',
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [
|
||||
{
|
||||
name: 'Edit Case Settings',
|
||||
id: 'cases_settings',
|
||||
includeIn: 'all',
|
||||
cases: {
|
||||
settings: ['securitySolutionFixture'],
|
||||
},
|
||||
savedObject: {
|
||||
all: [...filesSavedObjectTypes],
|
||||
read: [...filesSavedObjectTypes],
|
||||
},
|
||||
ui: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ const permissions = {
|
|||
delete: true,
|
||||
push: true,
|
||||
connectors: true,
|
||||
settings: true,
|
||||
};
|
||||
|
||||
const attachments = [{ type: AttachmentType.user as const, comment: 'test' }];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue