Skip to content

Commit

Permalink
[Cases] Close alerts if closure options is set to automatic (#127494)
Browse files Browse the repository at this point in the history
Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
cnasikas and kibanamachine authored Mar 15, 2022
1 parent def5ef5 commit fb89b86
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 2 deletions.
39 changes: 38 additions & 1 deletion x-pack/plugins/cases/server/client/cases/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import Boom from '@hapi/boom';
import { nodeBuilder } from '@kbn/es-query';
import { SavedObjectsFindResponse } from 'kibana/server';

import {
Expand All @@ -17,11 +18,18 @@ import {
CasesConfigureAttributes,
ActionTypes,
OWNER_FIELD,
CommentType,
CommentRequestAlertType,
} from '../../../common/api';
import { CASE_COMMENT_SAVED_OBJECT } from '../../../common/constants';

import { createIncident, getCommentContextFromAttributes } from './utils';
import { createCaseError } from '../../common/error';
import { flattenCaseSavedObject, getAlertInfoFromComments } from '../../common/utils';
import {
createAlertUpdateRequest,
flattenCaseSavedObject,
getAlertInfoFromComments,
} from '../../common/utils';
import { CasesClient, CasesClientArgs, CasesClientInternal } from '..';
import { Operations } from '../../authorization';
import { casesConnectors } from '../../connectors';
Expand All @@ -40,6 +48,30 @@ function shouldCloseByPush(
);
}

const changeAlertsStatusToClose = async (
caseId: string,
caseService: CasesClientArgs['caseService'],
alertsService: CasesClientArgs['alertsService']
) => {
const alertAttachments = (await caseService.getAllCaseComments({
id: [caseId],
options: {
filter: nodeBuilder.is(`${CASE_COMMENT_SAVED_OBJECT}.attributes.type`, CommentType.alert),
},
})) as SavedObjectsFindResponse<CommentRequestAlertType>;

const alerts = alertAttachments.saved_objects
.map((attachment) =>
createAlertUpdateRequest({
comment: attachment.attributes,
status: CaseStatuses.closed,
})
)
.flat();

await alertsService.updateAlertsStatus(alerts);
};

/**
* Parameters for pushing a case to an external system
*/
Expand Down Expand Up @@ -71,6 +103,7 @@ export const push = async (
caseService,
caseConfigureService,
userActionService,
alertsService,
actionsClient,
user,
logger,
Expand Down Expand Up @@ -224,6 +257,10 @@ export const push = async (
caseId,
owner: myCase.attributes.owner,
});

if (myCase.attributes.settings.syncAlerts) {
await changeAlertsStatusToClose(myCase.id, caseService, alertsService);
}
}

await userActionService.createUserAction({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ import {
getCase,
getServiceNowSimulationServer,
createConfiguration,
getSignalsWithES,
} from '../../../../common/lib/utils';
import { CaseConnector, CaseStatuses } from '../../../../../../plugins/cases/common/api';
import {
CaseConnector,
CaseStatuses,
CommentType,
} from '../../../../../../plugins/cases/common/api';
import {
globalRead,
noKibanaPrivileges,
Expand All @@ -50,6 +55,7 @@ import {
export default ({ getService }: FtrProviderContext): void => {
const supertest = getService('supertest');
const es = getService('es');
const esArchiver = getService('esArchiver');

describe('push_case', () => {
const actionsRemover = new ActionsRemover(supertest);
Expand Down Expand Up @@ -295,6 +301,103 @@ export default ({ getService }: FtrProviderContext): void => {
});
});

describe('alerts', () => {
const defaultSignalsIndex = '.siem-signals-default-000001';
const signalID = '4679431ee0ba3209b6fcd60a255a696886fe0a7d18f5375de510ff5b68fa6b78';
const signalID2 = '1023bcfea939643c5e51fd8df53797e0ea693cee547db579ab56d96402365c1e';

beforeEach(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/cases/signals/default');
});

afterEach(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/cases/signals/default');
await deleteAllCaseItems(es);
});

const attachAlertsAndPush = async ({ syncAlerts = true }: { syncAlerts?: boolean } = {}) => {
const { postedCase, connector } = await createCaseWithConnector({
createCaseReq: { ...getPostCaseRequest(), settings: { syncAlerts } },
configureReq: {
closure_type: 'close-by-pushing',
},
supertest,
serviceNowSimulatorURL,
actionsRemover,
});

await createComment({
supertest,
caseId: postedCase.id,
params: {
alertId: signalID,
index: defaultSignalsIndex,
rule: { id: 'test-rule-id', name: 'test-index-id' },
type: CommentType.alert,
owner: 'securitySolutionFixture',
},
});

await createComment({
supertest,
caseId: postedCase.id,
params: {
alertId: signalID2,
index: defaultSignalsIndex,
rule: { id: 'test-rule-id', name: 'test-index-id' },
type: CommentType.alert,
owner: 'securitySolutionFixture',
},
});

await pushCase({
supertest,
caseId: postedCase.id,
connectorId: connector.id,
});

await es.indices.refresh({ index: defaultSignalsIndex });

const signals = await getSignalsWithES({
es,
indices: defaultSignalsIndex,
ids: [signalID, signalID2],
});

return signals;
};

it('should change the status of all alerts attached to a case to closed when closure_type: close-by-pushing and syncAlerts: true', async () => {
const signals = await attachAlertsAndPush();
/**
* The status of the alerts should be changed to closed when pushing a case and the
* closure_type is set to close-by-pushing
*/
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal?.status).to.be(
CaseStatuses.closed
);

expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal?.status).to.be(
CaseStatuses.closed
);
});

it('should NOT change the status of all alerts attached to a case to closed when closure_type: close-by-pushing and syncAlerts: false', async () => {
const signals = await attachAlertsAndPush({ syncAlerts: false });
/**
* The status of the alerts should NOT be changed to closed when pushing a case and the
* closure_type is set to close-by-pushing and syncAlert is set to false
*/
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal?.status).to.be(
CaseStatuses.open
);

expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal?.status).to.be(
CaseStatuses.open
);
});
});

describe('rbac', () => {
const supertestWithoutAuth = getService('supertestWithoutAuth');

Expand Down

0 comments on commit fb89b86

Please sign in to comment.