Skip to content

Commit fcccb01

Browse files
authored
[Security Solution][Case] Add in-progress status to case (#84321)
1 parent 554ee9e commit fcccb01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+970
-428
lines changed

x-pack/plugins/case/common/api/cases/case.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,24 @@ import { CaseConnectorRt, ESCaseConnector, ConnectorPartialFieldsRt } from '../c
1515
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
1616
export { ActionTypeExecutorResult } from '../../../../actions/server/types';
1717

18-
const StatusRt = rt.union([rt.literal('open'), rt.literal('closed')]);
18+
export enum CaseStatuses {
19+
open = 'open',
20+
'in-progress' = 'in-progress',
21+
closed = 'closed',
22+
}
23+
24+
const CaseStatusRt = rt.union([
25+
rt.literal(CaseStatuses.open),
26+
rt.literal(CaseStatuses['in-progress']),
27+
rt.literal(CaseStatuses.closed),
28+
]);
29+
30+
export const caseStatuses = Object.values(CaseStatuses);
1931

2032
const CaseBasicRt = rt.type({
2133
connector: CaseConnectorRt,
2234
description: rt.string,
23-
status: StatusRt,
35+
status: CaseStatusRt,
2436
tags: rt.array(rt.string),
2537
title: rt.string,
2638
});
@@ -68,7 +80,7 @@ export const CaseExternalServiceRequestRt = CaseExternalServiceBasicRt;
6880

6981
export const CasesFindRequestRt = rt.partial({
7082
tags: rt.union([rt.array(rt.string), rt.string]),
71-
status: StatusRt,
83+
status: CaseStatusRt,
7284
reporters: rt.union([rt.array(rt.string), rt.string]),
7385
defaultSearchOperator: rt.union([rt.literal('AND'), rt.literal('OR')]),
7486
fields: rt.array(rt.string),
@@ -177,7 +189,6 @@ export type CasesResponse = rt.TypeOf<typeof CasesResponseRt>;
177189
export type CasesFindResponse = rt.TypeOf<typeof CasesFindResponseRt>;
178190
export type CasePatchRequest = rt.TypeOf<typeof CasePatchRequestRt>;
179191
export type CasesPatchRequest = rt.TypeOf<typeof CasesPatchRequestRt>;
180-
export type Status = rt.TypeOf<typeof StatusRt>;
181192
export type CaseExternalServiceRequest = rt.TypeOf<typeof CaseExternalServiceRequestRt>;
182193
export type ServiceConnectorCaseParams = rt.TypeOf<typeof ServiceConnectorCaseParamsRt>;
183194
export type ServiceConnectorCaseResponse = rt.TypeOf<typeof ServiceConnectorCaseResponseRt>;

x-pack/plugins/case/common/api/cases/status.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as rt from 'io-ts';
88

99
export const CasesStatusResponseRt = rt.type({
1010
count_open_cases: rt.number,
11+
count_in_progress_cases: rt.number,
1112
count_closed_cases: rt.number,
1213
});
1314

x-pack/plugins/case/server/client/cases/create.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { ConnectorTypes, CasePostRequest } from '../../../common/api';
7+
import { ConnectorTypes, CasePostRequest, CaseStatuses } from '../../../common/api';
88

99
import {
1010
createMockSavedObjectsRepository,
@@ -60,7 +60,7 @@ describe('create', () => {
6060
description: 'This is a brand new case of a bad meanie defacing data',
6161
external_service: null,
6262
title: 'Super Bad Security Issue',
63-
status: 'open',
63+
status: CaseStatuses.open,
6464
tags: ['defacement'],
6565
updated_at: null,
6666
updated_by: null,
@@ -126,7 +126,7 @@ describe('create', () => {
126126
description: 'This is a brand new case of a bad meanie defacing data',
127127
external_service: null,
128128
title: 'Super Bad Security Issue',
129-
status: 'open',
129+
status: CaseStatuses.open,
130130
tags: ['defacement'],
131131
updated_at: null,
132132
updated_by: null,
@@ -169,7 +169,7 @@ describe('create', () => {
169169
description: 'This is a brand new case of a bad meanie defacing data',
170170
external_service: null,
171171
title: 'Super Bad Security Issue',
172-
status: 'open',
172+
status: CaseStatuses.open,
173173
tags: ['defacement'],
174174
updated_at: null,
175175
updated_by: null,
@@ -316,7 +316,7 @@ describe('create', () => {
316316
title: 'a title',
317317
description: 'This is a brand new case of a bad meanie defacing data',
318318
tags: ['defacement'],
319-
status: 'closed',
319+
status: CaseStatuses.closed,
320320
connector: {
321321
id: 'none',
322322
name: 'none',

x-pack/plugins/case/server/client/cases/update.test.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { ConnectorTypes, CasesPatchRequest } from '../../../common/api';
7+
import { ConnectorTypes, CasesPatchRequest, CaseStatuses } from '../../../common/api';
88
import {
99
createMockSavedObjectsRepository,
1010
mockCaseNoConnectorId,
@@ -27,7 +27,7 @@ describe('update', () => {
2727
cases: [
2828
{
2929
id: 'mock-id-1',
30-
status: 'closed' as const,
30+
status: CaseStatuses.closed,
3131
version: 'WzAsMV0=',
3232
},
3333
],
@@ -56,7 +56,7 @@ describe('update', () => {
5656
description: 'This is a brand new case of a bad meanie defacing data',
5757
id: 'mock-id-1',
5858
external_service: null,
59-
status: 'closed',
59+
status: CaseStatuses.closed,
6060
tags: ['defacement'],
6161
title: 'Super Bad Security Issue',
6262
totalComment: 0,
@@ -79,8 +79,8 @@ describe('update', () => {
7979
username: 'awesome',
8080
},
8181
action_field: ['status'],
82-
new_value: 'closed',
83-
old_value: 'open',
82+
new_value: CaseStatuses.closed,
83+
old_value: CaseStatuses.open,
8484
},
8585
references: [
8686
{
@@ -98,15 +98,18 @@ describe('update', () => {
9898
cases: [
9999
{
100100
id: 'mock-id-1',
101-
status: 'open' as const,
101+
status: CaseStatuses.open,
102102
version: 'WzAsMV0=',
103103
},
104104
],
105105
};
106106

107107
const savedObjectsClient = createMockSavedObjectsRepository({
108108
caseSavedObject: [
109-
{ ...mockCases[0], attributes: { ...mockCases[0].attributes, status: 'closed' } },
109+
{
110+
...mockCases[0],
111+
attributes: { ...mockCases[0].attributes, status: CaseStatuses.closed },
112+
},
110113
...mockCases.slice(1),
111114
],
112115
});
@@ -130,7 +133,7 @@ describe('update', () => {
130133
description: 'This is a brand new case of a bad meanie defacing data',
131134
id: 'mock-id-1',
132135
external_service: null,
133-
status: 'open',
136+
status: CaseStatuses.open,
134137
tags: ['defacement'],
135138
title: 'Super Bad Security Issue',
136139
totalComment: 0,
@@ -146,7 +149,7 @@ describe('update', () => {
146149
cases: [
147150
{
148151
id: 'mock-no-connector_id',
149-
status: 'closed' as const,
152+
status: CaseStatuses.closed,
150153
version: 'WzAsMV0=',
151154
},
152155
],
@@ -177,7 +180,7 @@ describe('update', () => {
177180
description: 'This is a brand new case of a bad meanie defacing data',
178181
external_service: null,
179182
title: 'Super Bad Security Issue',
180-
status: 'closed',
183+
status: CaseStatuses.closed,
181184
tags: ['defacement'],
182185
updated_at: '2019-11-25T21:54:48.952Z',
183186
updated_by: { email: '[email protected]', full_name: 'Awesome D00d', username: 'awesome' },
@@ -231,7 +234,7 @@ describe('update', () => {
231234
description: 'Oh no, a bad meanie going LOLBins all over the place!',
232235
external_service: null,
233236
title: 'Another bad one',
234-
status: 'open',
237+
status: CaseStatuses.open,
235238
tags: ['LOLBins'],
236239
updated_at: '2019-11-25T21:54:48.952Z',
237240
updated_by: {
@@ -314,7 +317,7 @@ describe('update', () => {
314317
cases: [
315318
{
316319
id: 'mock-id-1',
317-
status: 'open' as const,
320+
status: CaseStatuses.open,
318321
version: 'WzAsMV0=',
319322
},
320323
],

x-pack/plugins/case/server/client/cases/update.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
ESCasePatchRequest,
2020
CasePatchRequest,
2121
CasesResponse,
22+
CaseStatuses,
2223
} from '../../../common/api';
2324
import { buildCaseUserActions } from '../../services/user_actions/helpers';
2425
import {
@@ -98,12 +99,15 @@ export const update = ({
9899
cases: updateFilterCases.map((thisCase) => {
99100
const { id: caseId, version, ...updateCaseAttributes } = thisCase;
100101
let closedInfo = {};
101-
if (updateCaseAttributes.status && updateCaseAttributes.status === 'closed') {
102+
if (updateCaseAttributes.status && updateCaseAttributes.status === CaseStatuses.closed) {
102103
closedInfo = {
103104
closed_at: updatedDt,
104105
closed_by: { email, full_name, username },
105106
};
106-
} else if (updateCaseAttributes.status && updateCaseAttributes.status === 'open') {
107+
} else if (
108+
updateCaseAttributes.status &&
109+
updateCaseAttributes.status === CaseStatuses.open
110+
) {
107111
closedInfo = {
108112
closed_at: null,
109113
closed_by: null,

x-pack/plugins/case/server/connectors/case/index.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Logger } from '../../../../../../src/core/server';
99
import { loggingSystemMock } from '../../../../../../src/core/server/mocks';
1010
import { actionsMock } from '../../../../actions/server/mocks';
1111
import { validateParams } from '../../../../actions/server/lib';
12-
import { ConnectorTypes, CommentType } from '../../../common/api';
12+
import { ConnectorTypes, CommentType, CaseStatuses } from '../../../common/api';
1313
import {
1414
createCaseServiceMock,
1515
createConfigureServiceMock,
@@ -785,7 +785,7 @@ describe('case connector', () => {
785785
tags: ['case', 'connector'],
786786
description: 'Yo fields!!',
787787
external_service: null,
788-
status: 'open' as const,
788+
status: CaseStatuses.open,
789789
updated_at: null,
790790
updated_by: null,
791791
version: 'WzksMV0=',
@@ -868,7 +868,7 @@ describe('case connector', () => {
868868
description: 'This is a brand new case of a bad meanie defacing data',
869869
id: 'mock-id-1',
870870
external_service: null,
871-
status: 'open' as const,
871+
status: CaseStatuses.open,
872872
tags: ['defacement'],
873873
title: 'Update title',
874874
totalComment: 0,
@@ -937,7 +937,7 @@ describe('case connector', () => {
937937
description: 'This is a brand new case of a bad meanie defacing data',
938938
external_service: null,
939939
title: 'Super Bad Security Issue',
940-
status: 'open' as const,
940+
status: CaseStatuses.open,
941941
tags: ['defacement'],
942942
updated_at: null,
943943
updated_by: null,

x-pack/plugins/case/server/routes/api/__fixtures__/mock_saved_objects.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
ESCaseAttributes,
1212
ConnectorTypes,
1313
CommentType,
14+
CaseStatuses,
1415
} from '../../../../common/api';
1516

1617
export const mockCases: Array<SavedObject<ESCaseAttributes>> = [
@@ -35,7 +36,7 @@ export const mockCases: Array<SavedObject<ESCaseAttributes>> = [
3536
description: 'This is a brand new case of a bad meanie defacing data',
3637
external_service: null,
3738
title: 'Super Bad Security Issue',
38-
status: 'open',
39+
status: CaseStatuses.open,
3940
tags: ['defacement'],
4041
updated_at: '2019-11-25T21:54:48.952Z',
4142
updated_by: {
@@ -69,7 +70,7 @@ export const mockCases: Array<SavedObject<ESCaseAttributes>> = [
6970
description: 'Oh no, a bad meanie destroying data!',
7071
external_service: null,
7172
title: 'Damaging Data Destruction Detected',
72-
status: 'open',
73+
status: CaseStatuses.open,
7374
tags: ['Data Destruction'],
7475
updated_at: '2019-11-25T22:32:00.900Z',
7576
updated_by: {
@@ -107,7 +108,7 @@ export const mockCases: Array<SavedObject<ESCaseAttributes>> = [
107108
description: 'Oh no, a bad meanie going LOLBins all over the place!',
108109
external_service: null,
109110
title: 'Another bad one',
110-
status: 'open',
111+
status: CaseStatuses.open,
111112
tags: ['LOLBins'],
112113
updated_at: '2019-11-25T22:32:17.947Z',
113114
updated_by: {
@@ -148,7 +149,7 @@ export const mockCases: Array<SavedObject<ESCaseAttributes>> = [
148149
},
149150
description: 'Oh no, a bad meanie going LOLBins all over the place!',
150151
external_service: null,
151-
status: 'closed',
152+
status: CaseStatuses.closed,
152153
title: 'Another bad one',
153154
tags: ['LOLBins'],
154155
updated_at: '2019-11-25T22:32:17.947Z',
@@ -179,7 +180,7 @@ export const mockCaseNoConnectorId: SavedObject<Partial<ESCaseAttributes>> = {
179180
description: 'This is a brand new case of a bad meanie defacing data',
180181
external_service: null,
181182
title: 'Super Bad Security Issue',
182-
status: 'open',
183+
status: CaseStatuses.open,
183184
tags: ['defacement'],
184185
updated_at: '2019-11-25T21:54:48.952Z',
185186
updated_by: {

x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ describe('FIND all cases', () => {
3838
const response = await routeHandler(theContext, request, kibanaResponseFactory);
3939
expect(response.status).toEqual(200);
4040
expect(response.payload.cases).toHaveLength(4);
41+
// mockSavedObjectsRepository do not support filters and returns all cases every time.
42+
expect(response.payload.count_open_cases).toEqual(4);
43+
expect(response.payload.count_closed_cases).toEqual(4);
44+
expect(response.payload.count_in_progress_cases).toEqual(4);
4145
});
4246

4347
it(`has proper connector id on cases with configured connector`, async () => {

x-pack/plugins/case/server/routes/api/cases/find_cases.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ import { fold } from 'fp-ts/lib/Either';
1111
import { identity } from 'fp-ts/lib/function';
1212

1313
import { isEmpty } from 'lodash';
14-
import { CasesFindResponseRt, CasesFindRequestRt, throwErrors } from '../../../../common/api';
14+
import {
15+
CasesFindResponseRt,
16+
CasesFindRequestRt,
17+
throwErrors,
18+
CaseStatuses,
19+
caseStatuses,
20+
} from '../../../../common/api';
1521
import { transformCases, sortToSnake, wrapError, escapeHatch } from '../utils';
1622
import { RouteDeps, TotalCommentByCase } from '../types';
1723
import { CASE_SAVED_OBJECT } from '../../../saved_object_types';
@@ -20,7 +26,7 @@ import { CASES_URL } from '../../../../common/constants';
2026
const combineFilters = (filters: string[], operator: 'OR' | 'AND'): string =>
2127
filters?.filter((i) => i !== '').join(` ${operator} `);
2228

23-
const getStatusFilter = (status: 'open' | 'closed', appendFilter?: string) =>
29+
const getStatusFilter = (status: CaseStatuses, appendFilter?: string) =>
2430
`${CASE_SAVED_OBJECT}.attributes.status: ${status}${
2531
!isEmpty(appendFilter) ? ` AND ${appendFilter}` : ''
2632
}`;
@@ -75,30 +81,21 @@ export function initFindCasesApi({ caseService, caseConfigureService, router }:
7581
client,
7682
};
7783

78-
const argsOpenCases = {
84+
const statusArgs = caseStatuses.map((caseStatus) => ({
7985
client,
8086
options: {
8187
fields: [],
8288
page: 1,
8389
perPage: 1,
84-
filter: getStatusFilter('open', myFilters),
90+
filter: getStatusFilter(caseStatus, myFilters),
8591
},
86-
};
92+
}));
8793

88-
const argsClosedCases = {
89-
client,
90-
options: {
91-
fields: [],
92-
page: 1,
93-
perPage: 1,
94-
filter: getStatusFilter('closed', myFilters),
95-
},
96-
};
97-
const [cases, openCases, closesCases] = await Promise.all([
94+
const [cases, openCases, inProgressCases, closedCases] = await Promise.all([
9895
caseService.findCases(args),
99-
caseService.findCases(argsOpenCases),
100-
caseService.findCases(argsClosedCases),
96+
...statusArgs.map((arg) => caseService.findCases(arg)),
10197
]);
98+
10299
const totalCommentsFindByCases = await Promise.all(
103100
cases.saved_objects.map((c) =>
104101
caseService.getAllCaseComments({
@@ -133,7 +130,8 @@ export function initFindCasesApi({ caseService, caseConfigureService, router }:
133130
transformCases(
134131
cases,
135132
openCases.total ?? 0,
136-
closesCases.total ?? 0,
133+
inProgressCases.total ?? 0,
134+
closedCases.total ?? 0,
137135
totalCommentsByCases
138136
)
139137
),

0 commit comments

Comments
 (0)