Skip to content

Commit

Permalink
[Security Solution][Case][Bug] Improve case logging (#91924) (#93022)
Browse files Browse the repository at this point in the history
* First pass at bringing in more logging

* Adding more logging to routes

* Adding more logging fixing tests

* Removing duplicate case string in logs

* Removing unneeded export

* Fixing type error

* Adding line breaks to make the messages more readable

* Fixing type errors

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
jonathan-buttner and kibanamachine authored Mar 1, 2021
1 parent ce18758 commit 73c8ea1
Show file tree
Hide file tree
Showing 53 changed files with 1,501 additions and 954 deletions.
6 changes: 4 additions & 2 deletions x-pack/plugins/case/server/client/alerts/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { ElasticsearchClient } from 'kibana/server';
import { ElasticsearchClient, Logger } from 'kibana/server';
import { AlertServiceContract } from '../../services';
import { CaseClientGetAlertsResponse } from './types';

Expand All @@ -14,19 +14,21 @@ interface GetParams {
ids: string[];
indices: Set<string>;
scopedClusterClient: ElasticsearchClient;
logger: Logger;
}

export const get = async ({
alertsService,
ids,
indices,
scopedClusterClient,
logger,
}: GetParams): Promise<CaseClientGetAlertsResponse> => {
if (ids.length === 0 || indices.size <= 0) {
return [];
}

const alerts = await alertsService.getAlerts({ ids, indices, scopedClusterClient });
const alerts = await alertsService.getAlerts({ ids, indices, scopedClusterClient, logger });
if (!alerts) {
return [];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('updateAlertsStatus', () => {

expect(caseClient.services.alertsService.updateAlertsStatus).toHaveBeenCalledWith({
scopedClusterClient: expect.anything(),
logger: expect.anything(),
ids: ['alert-id-1'],
indices: new Set<string>(['.siem-signals']),
status: CaseStatuses.closed,
Expand Down
6 changes: 4 additions & 2 deletions x-pack/plugins/case/server/client/alerts/update_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { ElasticsearchClient } from 'src/core/server';
import { ElasticsearchClient, Logger } from 'src/core/server';
import { CaseStatuses } from '../../../common/api';
import { AlertServiceContract } from '../../services';

Expand All @@ -15,6 +15,7 @@ interface UpdateAlertsStatusArgs {
status: CaseStatuses;
indices: Set<string>;
scopedClusterClient: ElasticsearchClient;
logger: Logger;
}

export const updateAlertsStatus = async ({
Expand All @@ -23,6 +24,7 @@ export const updateAlertsStatus = async ({
status,
indices,
scopedClusterClient,
logger,
}: UpdateAlertsStatusArgs): Promise<void> => {
await alertsService.updateAlertsStatus({ ids, status, indices, scopedClusterClient });
await alertsService.updateAlertsStatus({ ids, status, indices, scopedClusterClient, logger });
};
101 changes: 57 additions & 44 deletions x-pack/plugins/case/server/client/cases/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import { ConnectorTypes, CaseStatuses, CaseType, CaseClientPostRequest } from '../../../common/api';
import { isCaseError } from '../../common/error';

import {
createMockSavedObjectsRepository,
Expand Down Expand Up @@ -276,14 +277,16 @@ describe('create', () => {
caseSavedObject: mockCases,
});
const caseClient = await createCaseClientWithMockSavedObjectsClient({ savedObjectsClient });
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
});
return (
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
})
);
});

test('it throws when missing description', async () => {
Expand All @@ -303,14 +306,16 @@ describe('create', () => {
caseSavedObject: mockCases,
});
const caseClient = await createCaseClientWithMockSavedObjectsClient({ savedObjectsClient });
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
});
return (
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
})
);
});

test('it throws when missing tags', async () => {
Expand All @@ -330,14 +335,16 @@ describe('create', () => {
caseSavedObject: mockCases,
});
const caseClient = await createCaseClientWithMockSavedObjectsClient({ savedObjectsClient });
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
});
return (
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
})
);
});

test('it throws when missing connector ', async () => {
Expand All @@ -352,14 +359,16 @@ describe('create', () => {
caseSavedObject: mockCases,
});
const caseClient = await createCaseClientWithMockSavedObjectsClient({ savedObjectsClient });
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
});
return (
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
})
);
});

test('it throws when connector missing the right fields', async () => {
Expand All @@ -380,14 +389,16 @@ describe('create', () => {
caseSavedObject: mockCases,
});
const caseClient = await createCaseClientWithMockSavedObjectsClient({ savedObjectsClient });
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
});
return (
caseClient.client
// @ts-expect-error
.create({ theCase: postCase })
.catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
})
);
});

test('it throws if you passing status for a new case', async () => {
Expand All @@ -413,7 +424,7 @@ describe('create', () => {
caseSavedObject: mockCases,
});
const caseClient = await createCaseClientWithMockSavedObjectsClient({ savedObjectsClient });
caseClient.client.create(postCase).catch((e) => {
return caseClient.client.create(postCase).catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
Expand Down Expand Up @@ -441,10 +452,12 @@ describe('create', () => {
});
const caseClient = await createCaseClientWithMockSavedObjectsClient({ savedObjectsClient });

caseClient.client.create(postCase).catch((e) => {
return caseClient.client.create(postCase).catch((e) => {
expect(e).not.toBeNull();
expect(e.isBoom).toBe(true);
expect(e.output.statusCode).toBe(400);
expect(isCaseError(e)).toBeTruthy();
const boomErr = e.boomify();
expect(boomErr.isBoom).toBe(true);
expect(boomErr.output.statusCode).toBe(400);
});
});
});
Expand Down
80 changes: 45 additions & 35 deletions x-pack/plugins/case/server/client/cases/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { pipe } from 'fp-ts/lib/pipeable';
import { fold } from 'fp-ts/lib/Either';
import { identity } from 'fp-ts/lib/function';

import { SavedObjectsClientContract } from 'src/core/server';
import { SavedObjectsClientContract, Logger } from 'src/core/server';
import { flattenCaseSavedObject, transformNewCase } from '../../routes/api/utils';

import {
Expand All @@ -34,6 +34,7 @@ import {
CaseServiceSetup,
CaseUserActionServiceSetup,
} from '../../services';
import { createCaseError } from '../../common/error';

interface CreateCaseArgs {
caseConfigureService: CaseConfigureServiceSetup;
Expand All @@ -42,15 +43,20 @@ interface CreateCaseArgs {
savedObjectsClient: SavedObjectsClientContract;
userActionService: CaseUserActionServiceSetup;
theCase: CasePostRequest;
logger: Logger;
}

/**
* Creates a new case.
*/
export const create = async ({
savedObjectsClient,
caseService,
caseConfigureService,
userActionService,
user,
theCase,
logger,
}: CreateCaseArgs): Promise<CaseResponse> => {
// default to an individual case if the type is not defined.
const { type = CaseType.individual, ...nonTypeCaseFields } = theCase;
Expand All @@ -60,41 +66,45 @@ export const create = async ({
fold(throwErrors(Boom.badRequest), identity)
);

// eslint-disable-next-line @typescript-eslint/naming-convention
const { username, full_name, email } = user;
const createdDate = new Date().toISOString();
const myCaseConfigure = await caseConfigureService.find({ client: savedObjectsClient });
const caseConfigureConnector = getConnectorFromConfiguration(myCaseConfigure);

const newCase = await caseService.postNewCase({
client: savedObjectsClient,
attributes: transformNewCase({
createdDate,
newCase: query,
username,
full_name,
email,
connector: transformCaseConnectorToEsConnector(query.connector ?? caseConfigureConnector),
}),
});
try {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { username, full_name, email } = user;
const createdDate = new Date().toISOString();
const myCaseConfigure = await caseConfigureService.find({ client: savedObjectsClient });
const caseConfigureConnector = getConnectorFromConfiguration(myCaseConfigure);

await userActionService.postUserActions({
client: savedObjectsClient,
actions: [
buildCaseUserActionItem({
action: 'create',
actionAt: createdDate,
actionBy: { username, full_name, email },
caseId: newCase.id,
fields: ['description', 'status', 'tags', 'title', 'connector', 'settings'],
newValue: JSON.stringify(query),
const newCase = await caseService.postNewCase({
client: savedObjectsClient,
attributes: transformNewCase({
createdDate,
newCase: query,
username,
full_name,
email,
connector: transformCaseConnectorToEsConnector(query.connector ?? caseConfigureConnector),
}),
],
});
});

return CaseResponseRt.encode(
flattenCaseSavedObject({
savedObject: newCase,
})
);
await userActionService.postUserActions({
client: savedObjectsClient,
actions: [
buildCaseUserActionItem({
action: 'create',
actionAt: createdDate,
actionBy: { username, full_name, email },
caseId: newCase.id,
fields: ['description', 'status', 'tags', 'title', 'connector', 'settings'],
newValue: JSON.stringify(query),
}),
],
});

return CaseResponseRt.encode(
flattenCaseSavedObject({
savedObject: newCase,
})
);
} catch (error) {
throw createCaseError({ message: `Failed to create case: ${error}`, error, logger });
}
};
Loading

0 comments on commit 73c8ea1

Please sign in to comment.