Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[SIEM] [Cases] Shell scripts and unit tests #60183

Merged
merged 31 commits into from
Mar 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b9dd690
shouldve committed earlier damnit
stephmilovic Mar 7, 2020
354d94b
individual deleting complete
stephmilovic Mar 7, 2020
27a08cc
comment count implemented
stephmilovic Mar 7, 2020
20cfc98
add comment works
stephmilovic Mar 7, 2020
cc4d506
action reducer cleanup
stephmilovic Mar 7, 2020
f2abf92
more cleanups
stephmilovic Mar 7, 2020
7e98271
cleaning
stephmilovic Mar 9, 2020
65d0a36
Merge branch 'master' into delete-cases-cleanups
stephmilovic Mar 9, 2020
b7ce857
bulk delete
stephmilovic Mar 9, 2020
9b27a3b
clean up
stephmilovic Mar 9, 2020
48d49ff
fix plural on button text
stephmilovic Mar 9, 2020
4616822
fix tests and types
stephmilovic Mar 9, 2020
5b66897
merge in master
stephmilovic Mar 10, 2020
9965750
fixing
stephmilovic Mar 10, 2020
f625f5c
Merge branch 'master' into delete-cases-cleanups
stephmilovic Mar 10, 2020
3688b32
merge in master
stephmilovic Mar 10, 2020
ff6ff36
pr changes
stephmilovic Mar 10, 2020
b6731d5
init
stephmilovic Mar 11, 2020
3d33b41
fix conflicts
stephmilovic Mar 11, 2020
cfcb63d
Merge branch 'master' into delete-tests
stephmilovic Mar 12, 2020
ec39d4a
few more tests
stephmilovic Mar 12, 2020
d34e3cd
WIP on sh
stephmilovic Mar 12, 2020
e4573aa
mege in master
stephmilovic Mar 13, 2020
48a62cc
shell scripts added
stephmilovic Mar 14, 2020
d30b85d
shell scripts added
stephmilovic Mar 14, 2020
41f7334
add readme
stephmilovic Mar 14, 2020
d170148
fix test
stephmilovic Mar 16, 2020
c22ddcc
Merge branch 'master' into delete-tests
elasticmachine Mar 16, 2020
4b82a39
revert all cases tests
stephmilovic Mar 17, 2020
a950a03
Merge branch 'delete-tests' of github.com:stephmilovic/kibana into de…
stephmilovic Mar 17, 2020
314f7fa
Merge branch 'master' into delete-tests
elasticmachine Mar 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,7 @@ export const AllCases = React.memo(() => {
sort: { field: queryParams.sortField, direction: queryParams.sortOrder },
};
const euiBasicTableSelectionProps = useMemo<EuiTableSelectionType<Case>>(
() => ({
selectable: (item: Case) => true,
onSelectionChange: setSelectedCases,
}),
() => ({ onSelectionChange: setSelectedCases }),
[selectedCases]
);
const isCasesLoading = useMemo(
Expand Down Expand Up @@ -305,6 +302,7 @@ export const AllCases = React.memo(() => {
{i18n.SHOWING_SELECTED_CASES(selectedCases.length)}
</UtilityBarText>
<UtilityBarAction
data-test-subj="case-table-bulk-actions"
iconSide="right"
iconType="arrowDown"
popoverContent={getBulkItemsPopoverContent}
Expand All @@ -316,6 +314,7 @@ export const AllCases = React.memo(() => {
</UtilityBar>
<EuiBasicTable
columns={memoizedGetCasesColumns}
data-test-subj="all-cases-table"
isSelectable
itemId="id"
items={data.cases}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const getBulkItems = ({
<EuiContextMenuItem
key={i18n.BULK_ACTION_DELETE_SELECTED}
icon="trash"
disabled={selectedCaseIds.length === 0}
onClick={async () => {
closePopover();
deleteCasesAction(selectedCaseIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,30 @@
import React from 'react';
import { mount } from 'enzyme';
import { CaseComponent } from './';
import * as apiHook from '../../../../containers/case/use_update_case';
import * as updateHook from '../../../../containers/case/use_update_case';
import * as deleteHook from '../../../../containers/case/use_delete_cases';
import { caseProps, data } from './__mock__';
import { TestProviders } from '../../../../mock';

describe('CaseView ', () => {
const handleOnDeleteConfirm = jest.fn();
const handleToggleModal = jest.fn();
const dispatchResetIsDeleted = jest.fn();
const updateCaseProperty = jest.fn();
/* eslint-disable no-console */
// Silence until enzyme fixed to use ReactTestUtils.act()
const originalError = console.error;
beforeAll(() => {
console.error = jest.fn();
});
afterAll(() => {
console.error = originalError;
});
/* eslint-enable no-console */

beforeEach(() => {
jest.resetAllMocks();
jest.spyOn(apiHook, 'useUpdateCase').mockReturnValue({
jest.spyOn(updateHook, 'useUpdateCase').mockReturnValue({
caseData: data,
isLoading: false,
isError: false,
Expand Down Expand Up @@ -119,4 +133,46 @@ describe('CaseView ', () => {
.prop('source')
).toEqual(data.comments[0].comment);
});

it('toggle delete modal and cancel', () => {
const wrapper = mount(
<TestProviders>
<CaseComponent {...caseProps} />
</TestProviders>
);

expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeFalsy();

wrapper
.find(
'[data-test-subj="case-view-actions"] button[data-test-subj="property-actions-ellipses"]'
)
.first()
.simulate('click');
wrapper.find('button[data-test-subj="property-actions-trash"]').simulate('click');
expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeTruthy();
wrapper.find('button[data-test-subj="confirmModalCancelButton"]').simulate('click');
expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeFalsy();
});

it('toggle delete modal and confirm', () => {
jest.spyOn(deleteHook, 'useDeleteCases').mockReturnValue({
dispatchResetIsDeleted,
handleToggleModal,
handleOnDeleteConfirm,
isLoading: false,
isError: false,
isDeleted: false,
isDisplayConfirmDeleteModal: true,
});
const wrapper = mount(
<TestProviders>
<CaseComponent {...caseProps} />
</TestProviders>
);

expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeTruthy();
wrapper.find('button[data-test-subj="confirmModalConfirmButton"]').simulate('click');
expect(handleOnDeleteConfirm.mock.calls[0][0]).toEqual([caseProps.caseId]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export const CaseComponent = React.memo<CaseProps>(({ caseId, initialData }) =>
onChange={toggleStatusCase}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexItem grow={false} data-test-subj="case-view-actions">
<PropertyActions propertyActions={propertyActions} />
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const ConfirmDeleteCaseModalComp: React.FC<ConfirmDeleteCaseModalProps> = ({
buttonColor="danger"
cancelButtonText={i18n.CANCEL}
confirmButtonText={isPlural ? i18n.DELETE_CASES : i18n.DELETE_CASE}
data-test-subj="confirm-delete-case-modal"
defaultFocusedButton="confirm"
onCancel={onCancel}
onConfirm={onConfirm}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ export const Create = React.memo(() => {
}
}, [form]);

const handleSetIsCancel = useCallback(() => {
setIsCancel(true);
}, [isCancel]);

if (caseData != null && caseData.id) {
return <Redirect to={`/${SiemPageName.case}/${caseData.id}`} />;
}
Expand Down Expand Up @@ -137,7 +141,12 @@ export const Create = React.memo(() => {
responsive={false}
>
<EuiFlexItem grow={false}>
<EuiButtonEmpty size="s" onClick={() => setIsCancel(true)} iconType="cross">
<EuiButtonEmpty
data-test-subj="create-case-cancel"
size="s"
onClick={handleSetIsCancel}
iconType="cross"
>
{i18n.CANCEL}
</EuiButtonEmpty>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ export interface PropertyActionButtonProps {
label: string;
}

const ComponentId = 'property-actions';

const PropertyActionButton = React.memo<PropertyActionButtonProps>(
({ onClick, iconType, label }) => (
<EuiButtonEmpty
data-test-subj={`${ComponentId}-${iconType}`}
aria-label={label}
color="text"
iconSide="left"
Expand Down Expand Up @@ -48,13 +51,13 @@ export const PropertyActions = React.memo<PropertyActionsProps>(({ propertyActio
}, []);

return (
<EuiFlexGroup alignItems="flexStart" data-test-subj="properties-right" gutterSize="none">
<EuiFlexGroup alignItems="flexStart" data-test-subj={ComponentId} gutterSize="none">
<EuiFlexItem grow={false}>
<EuiPopover
anchorPosition="downRight"
button={
<EuiButtonIcon
data-test-subj="ellipses"
data-test-subj={`${ComponentId}-ellipses`}
aria-label="Actions"
iconType="boxesHorizontal"
onClick={onButtonClick}
Expand All @@ -64,7 +67,12 @@ export const PropertyActions = React.memo<PropertyActionsProps>(({ propertyActio
isOpen={showActions}
closePopover={onClosePopover}
>
<EuiFlexGroup alignItems="flexStart" direction="column" gutterSize="none">
<EuiFlexGroup
alignItems="flexStart"
data-test-subj={`${ComponentId}-group`}
direction="column"
gutterSize="none"
>
{propertyActions.map((action, key) => (
<EuiFlexItem grow={false} key={`${action.label}${key}`}>
<PropertyActionButton
Expand Down
90 changes: 90 additions & 0 deletions x-pack/plugins/case/server/scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
README.md for developers working on the Case API on how to get started
using the CURL scripts in the scripts folder.

The scripts rely on CURL and jq:

- [CURL](https://curl.haxx.se)
- [jq](https://stedolan.github.io/jq/)

Install curl and jq

```sh
brew update
brew install curl
brew install jq
```

Open `$HOME/.zshrc` or `${HOME}.bashrc` depending on your SHELL output from `echo $SHELL`
and add these environment variables:

```sh
export ELASTICSEARCH_USERNAME=${user}
export ELASTICSEARCH_PASSWORD=${password}
export ELASTICSEARCH_URL=https://${ip}:9200
export KIBANA_URL=http://localhost:5601
export TASK_MANAGER_INDEX=.kibana-task-manager-${your user id}
export KIBANA_INDEX=.kibana-${your user id}
```

source `$HOME/.zshrc` or `${HOME}.bashrc` to ensure variables are set:

```sh
source ~/.zshrc
```

Restart Kibana and ensure that you are using `--no-base-path` as changing the base path is a feature but will
get in the way of the CURL scripts written as is.

Go to the scripts folder `cd kibana/x-pack/plugins/case/server/scripts` and run:

```sh
./hard_reset.sh
Copy link
Contributor

Choose a reason for hiding this comment

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

I followed the step here but was unable to complete this. Would like to know if we need to set SPACE_URL in .bashrc as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

Had another try, and it was done successfully!

```

which will:

- Delete any existing cases you have
- Delete any existing comments you have
- Posts the sample case from `./mock/case/post_case.json`
- Posts the sample comment from `./mock/comment/post_comment.json` to the new case

Now you can run

```sh
./find_cases.sh
```

You should see the new case created like so:

```sh
{
"page": 1,
"per_page": 20,
"total": 1,
"cases": [
{
"id": "2e0afbc0-658c-11ea-85c8-1d8f792cbc08",
"version": "Wzc5NSwxXQ==",
"comments": [],
"comment_ids": [
"2ecec0f0-658c-11ea-85c8-1d8f792cbc08"
],
"created_at": "2020-03-14T00:38:53.004Z",
"created_by": {
"full_name": "Steph Milovic",
"username": "smilovic"
},
"updated_at": null,
"updated_by": null,
"description": "This looks not so good",
"title": "Bad meanie defacing data",
"status": "open",
"tags": [
"defacement"
]
}
],
"count_open_cases": 1,
"count_closed_cases": 1
}
```
41 changes: 41 additions & 0 deletions x-pack/plugins/case/server/scripts/check_env_variables.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/sh

#
# 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.
#

# Add this to the start of any scripts to detect if env variables are set

set -e

if [ -z "${ELASTICSEARCH_USERNAME}" ]; then
echo "Set ELASTICSEARCH_USERNAME in your environment"
exit 1
fi

if [ -z "${ELASTICSEARCH_PASSWORD}" ]; then
echo "Set ELASTICSEARCH_PASSWORD in your environment"
exit 1
fi

if [ -z "${ELASTICSEARCH_URL}" ]; then
echo "Set ELASTICSEARCH_URL in your environment"
exit 1
fi

if [ -z "${KIBANA_URL}" ]; then
echo "Set KIBANA_URL in your environment"
exit 1
fi

if [ -z "${TASK_MANAGER_INDEX}" ]; then
echo "Set TASK_MANAGER_INDEX in your environment"
exit 1
fi

if [ -z "${KIBANA_INDEX}" ]; then
echo "Set KIBANA_INDEX in your environment"
exit 1
fi
51 changes: 51 additions & 0 deletions x-pack/plugins/case/server/scripts/delete_cases.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/sh

#
# 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.
#

# Creates a new case and then gets it if no CASE_ID is specified

# Example:
# ./delete_cases.sh

# Example with CASE_ID args:
# ./delete_cases.sh 1234-example-id 5678-example-id

set -e
./check_env_variables.sh

if [ "$1" ]; then
ALL=("$@")
i=0

COUNT=${#ALL[@]}
IDS=""
for ID in "${ALL[@]}"
do
let i=i+1
if [ $i -eq $COUNT ]; then
IDS+="%22${ID}%22"
else
IDS+="%22${ID}%22,"
fi
done

curl -s -k \
-H 'kbn-xsrf: 123' \
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
-X DELETE "${KIBANA_URL}${SPACE_URL}/api/cases?ids=\[${IDS}\]" \
| jq .;
exit 1
else
CASE_ID=("$(./generate_case_data.sh | jq '.id' -j)")
curl -s -k \
-H 'Content-Type: application/json' \
-H 'kbn-xsrf: 123' \
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
-X DELETE "${KIBANA_URL}${SPACE_URL}/api/cases?ids=\[%22${CASE_ID}%22\]" \
| jq .;
exit 1
fi
Loading