Skip to content

Commit

Permalink
[SIEM] [Cases] External service selection per case (#64775) (#65258)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephmilovic authored May 5, 2020
1 parent 5dc8610 commit 4b4bab7
Show file tree
Hide file tree
Showing 54 changed files with 1,726 additions and 359 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/case/common/api/cases/case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export { ActionTypeExecutorResult } from '../../../../actions/server/types';
const StatusRt = rt.union([rt.literal('open'), rt.literal('closed')]);

const CaseBasicRt = rt.type({
connector_id: rt.string,
description: rt.string,
status: StatusRt,
tags: rt.array(rt.string),
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/case/common/api/cases/user_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { UserRT } from '../user';
const UserActionFieldRt = rt.array(
rt.union([
rt.literal('comment'),
rt.literal('connector_id'),
rt.literal('description'),
rt.literal('pushed'),
rt.literal('tags'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const mockCases: Array<SavedObject<CaseAttributes>> = [
attributes: {
closed_at: null,
closed_by: null,
connector_id: 'none',
created_at: '2019-11-25T21:54:48.952Z',
created_by: {
full_name: 'elastic',
Expand Down Expand Up @@ -46,6 +47,7 @@ export const mockCases: Array<SavedObject<CaseAttributes>> = [
attributes: {
closed_at: null,
closed_by: null,
connector_id: 'none',
created_at: '2019-11-25T22:32:00.900Z',
created_by: {
full_name: 'elastic',
Expand Down Expand Up @@ -74,6 +76,7 @@ export const mockCases: Array<SavedObject<CaseAttributes>> = [
attributes: {
closed_at: null,
closed_by: null,
connector_id: '123',
created_at: '2019-11-25T22:32:17.947Z',
created_by: {
full_name: 'elastic',
Expand Down Expand Up @@ -106,6 +109,7 @@ export const mockCases: Array<SavedObject<CaseAttributes>> = [
email: '[email protected]',
username: 'elastic',
},
connector_id: '123',
created_at: '2019-11-25T22:32:17.947Z',
created_by: {
full_name: 'elastic',
Expand All @@ -130,6 +134,35 @@ export const mockCases: Array<SavedObject<CaseAttributes>> = [
},
];

export const mockCaseNoConnectorId: SavedObject<Partial<CaseAttributes>> = {
type: 'cases',
id: 'mock-no-connector_id',
attributes: {
closed_at: null,
closed_by: null,
created_at: '2019-11-25T21:54:48.952Z',
created_by: {
full_name: 'elastic',
email: '[email protected]',
username: 'elastic',
},
description: 'This is a brand new case of a bad meanie defacing data',
external_service: null,
title: 'Super Bad Security Issue',
status: 'open',
tags: ['defacement'],
updated_at: '2019-11-25T21:54:48.952Z',
updated_by: {
full_name: 'elastic',
email: '[email protected]',
username: 'elastic',
},
},
references: [],
updated_at: '2019-11-25T21:54:48.952Z',
version: 'WzAsMV0=',
};

export const mockCasesErrorTriggerData = [
{
id: 'valid-id',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ import { buildCommentUserActionItem } from '../../../../services/user_actions/he
import { RouteDeps } from '../../types';
import { escapeHatch, wrapError, flattenCaseSavedObject } from '../../utils';
import { CASE_COMMENTS_URL } from '../../../../../common/constants';
import { getConnectorId } from '../helpers';

export function initPatchCommentApi({ caseService, router, userActionService }: RouteDeps) {
export function initPatchCommentApi({
caseConfigureService,
caseService,
router,
userActionService,
}: RouteDeps) {
router.patch(
{
path: CASE_COMMENTS_URL,
Expand Down Expand Up @@ -64,7 +70,7 @@ export function initPatchCommentApi({ caseService, router, userActionService }:

const { username, full_name, email } = await caseService.getUser({ request, response });
const updatedDate = new Date().toISOString();
const [updatedComment, updatedCase] = await Promise.all([
const [updatedComment, updatedCase, myCaseConfigure] = await Promise.all([
caseService.patchComment({
client,
commentId: query.id,
Expand All @@ -84,6 +90,7 @@ export function initPatchCommentApi({ caseService, router, userActionService }:
},
version: myCase.version,
}),
caseConfigureService.find({ client }),
]);

const totalCommentsFindByCases = await caseService.getAllCaseComments({
Expand All @@ -95,7 +102,7 @@ export function initPatchCommentApi({ caseService, router, userActionService }:
perPage: 1,
},
});

const caseConfigureConnectorId = getConnectorId(myCaseConfigure);
const [comments] = await Promise.all([
caseService.getAllCaseComments({
client,
Expand Down Expand Up @@ -125,16 +132,17 @@ export function initPatchCommentApi({ caseService, router, userActionService }:

return response.ok({
body: CaseResponseRt.encode(
flattenCaseSavedObject(
{
flattenCaseSavedObject({
savedObject: {
...myCase,
...updatedCase,
attributes: { ...myCase.attributes, ...updatedCase.attributes },
version: updatedCase.version ?? myCase.version,
references: myCase.references,
},
comments.saved_objects
)
comments: comments.saved_objects,
caseConfigureConnectorId,
})
),
});
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ import { buildCommentUserActionItem } from '../../../../services/user_actions/he
import { escapeHatch, transformNewComment, wrapError, flattenCaseSavedObject } from '../../utils';
import { RouteDeps } from '../../types';
import { CASE_COMMENTS_URL } from '../../../../../common/constants';
import { getConnectorId } from '../helpers';

export function initPostCommentApi({ caseService, router, userActionService }: RouteDeps) {
export function initPostCommentApi({
caseConfigureService,
caseService,
router,
userActionService,
}: RouteDeps) {
router.post(
{
path: CASE_COMMENTS_URL,
Expand Down Expand Up @@ -45,7 +51,7 @@ export function initPostCommentApi({ caseService, router, userActionService }: R
const { username, full_name, email } = await caseService.getUser({ request, response });
const createdDate = new Date().toISOString();

const [newComment, updatedCase] = await Promise.all([
const [newComment, updatedCase, myCaseConfigure] = await Promise.all([
caseService.postNewComment({
client,
attributes: transformNewComment({
Expand All @@ -72,8 +78,10 @@ export function initPostCommentApi({ caseService, router, userActionService }: R
},
version: myCase.version,
}),
caseConfigureService.find({ client }),
]);

const caseConfigureConnectorId = getConnectorId(myCaseConfigure);
const totalCommentsFindByCases = await caseService.getAllCaseComments({
client,
caseId,
Expand Down Expand Up @@ -112,16 +120,17 @@ export function initPostCommentApi({ caseService, router, userActionService }: R

return response.ok({
body: CaseResponseRt.encode(
flattenCaseSavedObject(
{
flattenCaseSavedObject({
savedObject: {
...myCase,
...updatedCase,
attributes: { ...myCase.attributes, ...updatedCase.attributes },
version: updatedCase.version ?? myCase.version,
references: myCase.references,
},
comments.saved_objects
)
comments: comments.saved_objects,
caseConfigureConnectorId,
})
),
});
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { RouteDeps } from '../../types';
import { wrapError } from '../../utils';
import { CASE_CONFIGURE_URL } from '../../../../../common/constants';

export function initGetCaseConfigure({ caseConfigureService, caseService, router }: RouteDeps) {
export function initGetCaseConfigure({ caseConfigureService, router }: RouteDeps) {
router.get(
{
path: CASE_CONFIGURE_URL,
Expand Down
52 changes: 51 additions & 1 deletion x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import {
} from '../__fixtures__';
import { initFindCasesApi } from './find_cases';
import { CASES_URL } from '../../../../common/constants';
import { mockCaseConfigure, mockCaseNoConnectorId } from '../__fixtures__/mock_saved_objects';

describe('GET all cases', () => {
describe('FIND all cases', () => {
let routeHandler: RequestHandler<any, any, any>;
beforeAll(async () => {
routeHandler = await createRoute(initFindCasesApi, 'get');
Expand All @@ -37,4 +38,53 @@ describe('GET all cases', () => {
expect(response.status).toEqual(200);
expect(response.payload.cases).toHaveLength(4);
});
it(`has proper connector id on cases with configured id`, async () => {
const request = httpServerMock.createKibanaRequest({
path: `${CASES_URL}/_find`,
method: 'get',
});

const theContext = createRouteContext(
createMockSavedObjectsRepository({
caseSavedObject: mockCases,
})
);

const response = await routeHandler(theContext, request, kibanaResponseFactory);
expect(response.status).toEqual(200);
expect(response.payload.cases[2].connector_id).toEqual('123');
});
it(`adds 'none' connector id to cases without when 3rd party unconfigured`, async () => {
const request = httpServerMock.createKibanaRequest({
path: `${CASES_URL}/_find`,
method: 'get',
});

const theContext = createRouteContext(
createMockSavedObjectsRepository({
caseSavedObject: [mockCaseNoConnectorId],
})
);

const response = await routeHandler(theContext, request, kibanaResponseFactory);
expect(response.status).toEqual(200);
expect(response.payload.cases[0].connector_id).toEqual('none');
});
it(`adds default connector id to cases without when 3rd party configured`, async () => {
const request = httpServerMock.createKibanaRequest({
path: `${CASES_URL}/_find`,
method: 'get',
});

const theContext = createRouteContext(
createMockSavedObjectsRepository({
caseSavedObject: [mockCaseNoConnectorId],
caseConfigureSavedObject: mockCaseConfigure,
})
);

const response = await routeHandler(theContext, request, kibanaResponseFactory);
expect(response.status).toEqual(200);
expect(response.payload.cases[0].connector_id).toEqual('123');
});
});
10 changes: 6 additions & 4 deletions x-pack/plugins/case/server/routes/api/cases/find_cases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { transformCases, sortToSnake, wrapError, escapeHatch } from '../utils';
import { RouteDeps, TotalCommentByCase } from '../types';
import { CASE_SAVED_OBJECT } from '../../../saved_object_types';
import { CASES_URL } from '../../../../common/constants';
import { getConnectorId } from './helpers';

const combineFilters = (filters: string[], operator: 'OR' | 'AND'): string =>
filters?.filter(i => i !== '').join(` ${operator} `);
Expand All @@ -39,7 +40,7 @@ const buildFilter = (
: `${CASE_SAVED_OBJECT}.attributes.${field}: ${filters}`
: '';

export function initFindCasesApi({ caseService, router }: RouteDeps) {
export function initFindCasesApi({ caseService, caseConfigureService, router }: RouteDeps) {
router.get(
{
path: `${CASES_URL}/_find`,
Expand Down Expand Up @@ -94,12 +95,12 @@ export function initFindCasesApi({ caseService, router }: RouteDeps) {
filter: getStatusFilter('closed', myFilters),
},
};
const [cases, openCases, closesCases] = await Promise.all([
const [cases, openCases, closesCases, myCaseConfigure] = await Promise.all([
caseService.findCases(args),
caseService.findCases(argsOpenCases),
caseService.findCases(argsClosedCases),
caseConfigureService.find({ client }),
]);

const totalCommentsFindByCases = await Promise.all(
cases.saved_objects.map(c =>
caseService.getAllCaseComments({
Expand Down Expand Up @@ -135,7 +136,8 @@ export function initFindCasesApi({ caseService, router }: RouteDeps) {
cases,
openCases.total ?? 0,
closesCases.total ?? 0,
totalCommentsByCases
totalCommentsByCases,
getConnectorId(myCaseConfigure)
)
),
});
Expand Down
Loading

0 comments on commit 4b4bab7

Please sign in to comment.