mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[SIEM] Import timeline schema update (#61622)
* allow users importing data if they are authorized * rename props * rename types * hide import timeline btn if unauthorized * unit test for TimelinesPageComponent * update schemas * update schema Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
1855d10d9d
commit
c0c9d98538
3 changed files with 117 additions and 31 deletions
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TimelinesPageComponent } from './timelines_page';
|
||||||
|
import { useKibana } from '../../lib/kibana';
|
||||||
|
import { shallow, ShallowWrapper } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
import ApolloClient from 'apollo-client';
|
||||||
|
|
||||||
|
jest.mock('../../lib/kibana', () => {
|
||||||
|
return {
|
||||||
|
useKibana: jest.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
describe('TimelinesPageComponent', () => {
|
||||||
|
const mockAppollloClient = {} as ApolloClient<object>;
|
||||||
|
let wrapper: ShallowWrapper;
|
||||||
|
|
||||||
|
describe('If the user is authorised', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
((useKibana as unknown) as jest.Mock).mockReturnValue({
|
||||||
|
services: {
|
||||||
|
application: {
|
||||||
|
capabilities: {
|
||||||
|
siem: {
|
||||||
|
crud: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
wrapper = shallow(<TimelinesPageComponent apolloClient={mockAppollloClient} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
((useKibana as unknown) as jest.Mock).mockReset();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show the import timeline modal by default', () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('[data-test-subj="stateful-open-timeline"]').prop('importDataModalToggle')
|
||||||
|
).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show the import timeline button', () => {
|
||||||
|
expect(wrapper.find('[data-test-subj="open-import-data-modal-btn"]').exists()).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show the import timeline modal after user clicking on the button', () => {
|
||||||
|
wrapper.find('[data-test-subj="open-import-data-modal-btn"]').simulate('click');
|
||||||
|
expect(
|
||||||
|
wrapper.find('[data-test-subj="stateful-open-timeline"]').prop('importDataModalToggle')
|
||||||
|
).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('If the user is not authorised', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
((useKibana as unknown) as jest.Mock).mockReturnValue({
|
||||||
|
services: {
|
||||||
|
application: {
|
||||||
|
capabilities: {
|
||||||
|
siem: {
|
||||||
|
crud: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
wrapper = shallow(<TimelinesPageComponent apolloClient={mockAppollloClient} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
((useKibana as unknown) as jest.Mock).mockReset();
|
||||||
|
});
|
||||||
|
test('should not show the import timeline modal by default', () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('[data-test-subj="stateful-open-timeline"]').prop('importDataModalToggle')
|
||||||
|
).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show the import timeline button', () => {
|
||||||
|
expect(wrapper.find('[data-test-subj="open-import-data-modal-btn"]').exists()).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -28,7 +28,7 @@ type OwnProps = TimelinesProps;
|
||||||
|
|
||||||
export const DEFAULT_SEARCH_RESULTS_PER_PAGE = 10;
|
export const DEFAULT_SEARCH_RESULTS_PER_PAGE = 10;
|
||||||
|
|
||||||
const TimelinesPageComponent: React.FC<OwnProps> = ({ apolloClient }) => {
|
export const TimelinesPageComponent: React.FC<OwnProps> = ({ apolloClient }) => {
|
||||||
const [importDataModalToggle, setImportDataModalToggle] = useState<boolean>(false);
|
const [importDataModalToggle, setImportDataModalToggle] = useState<boolean>(false);
|
||||||
const onImportTimelineBtnClick = useCallback(() => {
|
const onImportTimelineBtnClick = useCallback(() => {
|
||||||
setImportDataModalToggle(true);
|
setImportDataModalToggle(true);
|
||||||
|
@ -43,7 +43,11 @@ const TimelinesPageComponent: React.FC<OwnProps> = ({ apolloClient }) => {
|
||||||
<WrapperPage>
|
<WrapperPage>
|
||||||
<HeaderPage border title={i18n.PAGE_TITLE}>
|
<HeaderPage border title={i18n.PAGE_TITLE}>
|
||||||
{capabilitiesCanUserCRUD && (
|
{capabilitiesCanUserCRUD && (
|
||||||
<EuiButton iconType="indexOpen" onClick={onImportTimelineBtnClick}>
|
<EuiButton
|
||||||
|
iconType="indexOpen"
|
||||||
|
onClick={onImportTimelineBtnClick}
|
||||||
|
data-test-subj="open-import-data-modal-btn"
|
||||||
|
>
|
||||||
{i18n.ALL_TIMELINES_IMPORT_TIMELINE_TITLE}
|
{i18n.ALL_TIMELINES_IMPORT_TIMELINE_TITLE}
|
||||||
</EuiButton>
|
</EuiButton>
|
||||||
)}
|
)}
|
||||||
|
@ -57,6 +61,7 @@ const TimelinesPageComponent: React.FC<OwnProps> = ({ apolloClient }) => {
|
||||||
importDataModalToggle={importDataModalToggle && capabilitiesCanUserCRUD}
|
importDataModalToggle={importDataModalToggle && capabilitiesCanUserCRUD}
|
||||||
setImportDataModalToggle={setImportDataModalToggle}
|
setImportDataModalToggle={setImportDataModalToggle}
|
||||||
title={i18n.ALL_TIMELINES_PANEL_TITLE}
|
title={i18n.ALL_TIMELINES_PANEL_TITLE}
|
||||||
|
data-test-subj="stateful-open-timeline"
|
||||||
/>
|
/>
|
||||||
</TimelinesContainer>
|
</TimelinesContainer>
|
||||||
</WrapperPage>
|
</WrapperPage>
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
import Joi from 'joi';
|
import Joi from 'joi';
|
||||||
|
|
||||||
const allowEmptyString = Joi.string().allow([null, '']);
|
const allowEmptyString = Joi.string().allow([null, '']);
|
||||||
const columnHeaderType = Joi.string();
|
const columnHeaderType = allowEmptyString;
|
||||||
export const created = Joi.number().allow(null);
|
export const created = Joi.number().allow(null);
|
||||||
export const createdBy = Joi.string();
|
export const createdBy = allowEmptyString;
|
||||||
|
|
||||||
export const description = allowEmptyString;
|
export const description = allowEmptyString;
|
||||||
export const end = Joi.number();
|
export const end = Joi.number();
|
||||||
export const eventId = allowEmptyString;
|
export const eventId = allowEmptyString;
|
||||||
export const eventType = Joi.string();
|
export const eventType = allowEmptyString;
|
||||||
|
|
||||||
export const filters = Joi.array()
|
export const filters = Joi.array()
|
||||||
.items(
|
.items(
|
||||||
|
@ -24,19 +24,11 @@ export const filters = Joi.array()
|
||||||
disabled: Joi.boolean().allow(null),
|
disabled: Joi.boolean().allow(null),
|
||||||
field: allowEmptyString,
|
field: allowEmptyString,
|
||||||
formattedValue: allowEmptyString,
|
formattedValue: allowEmptyString,
|
||||||
index: {
|
index: allowEmptyString,
|
||||||
type: 'keyword',
|
key: allowEmptyString,
|
||||||
},
|
negate: Joi.boolean().allow(null),
|
||||||
key: {
|
|
||||||
type: 'keyword',
|
|
||||||
},
|
|
||||||
negate: {
|
|
||||||
type: 'boolean',
|
|
||||||
},
|
|
||||||
params: allowEmptyString,
|
params: allowEmptyString,
|
||||||
type: {
|
type: allowEmptyString,
|
||||||
type: 'keyword',
|
|
||||||
},
|
|
||||||
value: allowEmptyString,
|
value: allowEmptyString,
|
||||||
}),
|
}),
|
||||||
exists: allowEmptyString,
|
exists: allowEmptyString,
|
||||||
|
@ -68,22 +60,22 @@ export const version = allowEmptyString;
|
||||||
export const columns = Joi.array().items(
|
export const columns = Joi.array().items(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
aggregatable: Joi.boolean().allow(null),
|
aggregatable: Joi.boolean().allow(null),
|
||||||
category: Joi.string(),
|
category: allowEmptyString,
|
||||||
columnHeaderType,
|
columnHeaderType,
|
||||||
description,
|
description,
|
||||||
example: allowEmptyString,
|
example: allowEmptyString,
|
||||||
indexes: allowEmptyString,
|
indexes: allowEmptyString,
|
||||||
id: Joi.string(),
|
id: allowEmptyString,
|
||||||
name,
|
name,
|
||||||
placeholder: allowEmptyString,
|
placeholder: allowEmptyString,
|
||||||
searchable: Joi.boolean().allow(null),
|
searchable: Joi.boolean().allow(null),
|
||||||
type: Joi.string(),
|
type: allowEmptyString,
|
||||||
}).required()
|
}).required()
|
||||||
);
|
);
|
||||||
export const dataProviders = Joi.array()
|
export const dataProviders = Joi.array()
|
||||||
.items(
|
.items(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
id: Joi.string(),
|
id: allowEmptyString,
|
||||||
name: allowEmptyString,
|
name: allowEmptyString,
|
||||||
enabled: Joi.boolean().allow(null),
|
enabled: Joi.boolean().allow(null),
|
||||||
excluded: Joi.boolean().allow(null),
|
excluded: Joi.boolean().allow(null),
|
||||||
|
@ -98,7 +90,7 @@ export const dataProviders = Joi.array()
|
||||||
and: Joi.array()
|
and: Joi.array()
|
||||||
.items(
|
.items(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
id: Joi.string(),
|
id: allowEmptyString,
|
||||||
name,
|
name,
|
||||||
enabled: Joi.boolean().allow(null),
|
enabled: Joi.boolean().allow(null),
|
||||||
excluded: Joi.boolean().allow(null),
|
excluded: Joi.boolean().allow(null),
|
||||||
|
@ -122,9 +114,9 @@ export const dateRange = Joi.object({
|
||||||
});
|
});
|
||||||
export const favorite = Joi.array().items(
|
export const favorite = Joi.array().items(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
keySearch: Joi.string(),
|
keySearch: allowEmptyString,
|
||||||
fullName: Joi.string(),
|
fullName: allowEmptyString,
|
||||||
userName: Joi.string(),
|
userName: allowEmptyString,
|
||||||
favoriteDate: Joi.number(),
|
favoriteDate: Joi.number(),
|
||||||
}).allow(null)
|
}).allow(null)
|
||||||
);
|
);
|
||||||
|
@ -141,26 +133,26 @@ const noteItem = Joi.object({
|
||||||
});
|
});
|
||||||
export const eventNotes = Joi.array().items(noteItem);
|
export const eventNotes = Joi.array().items(noteItem);
|
||||||
export const globalNotes = Joi.array().items(noteItem);
|
export const globalNotes = Joi.array().items(noteItem);
|
||||||
export const kqlMode = Joi.string();
|
export const kqlMode = allowEmptyString;
|
||||||
export const kqlQuery = Joi.object({
|
export const kqlQuery = Joi.object({
|
||||||
filterQuery: Joi.object({
|
filterQuery: Joi.object({
|
||||||
kuery: Joi.object({
|
kuery: Joi.object({
|
||||||
kind: Joi.string(),
|
kind: allowEmptyString,
|
||||||
expression: allowEmptyString,
|
expression: allowEmptyString,
|
||||||
}),
|
}),
|
||||||
serializedQuery: allowEmptyString,
|
serializedQuery: allowEmptyString,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
export const pinnedEventIds = Joi.array()
|
export const pinnedEventIds = Joi.array()
|
||||||
.items(Joi.string())
|
.items(allowEmptyString)
|
||||||
.allow(null);
|
.allow(null);
|
||||||
export const sort = Joi.object({
|
export const sort = Joi.object({
|
||||||
columnId: Joi.string(),
|
columnId: allowEmptyString,
|
||||||
sortDirection: Joi.string(),
|
sortDirection: allowEmptyString,
|
||||||
});
|
});
|
||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
|
|
||||||
export const ids = Joi.array().items(Joi.string());
|
export const ids = Joi.array().items(allowEmptyString);
|
||||||
|
|
||||||
export const exclude_export_details = Joi.boolean();
|
export const exclude_export_details = Joi.boolean();
|
||||||
export const file_name = allowEmptyString;
|
export const file_name = allowEmptyString;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue