[Cases] Adding feature flag for sub cases (#95122)
* Adding feature flag for sub cases * Disabling case as a connector in security solution * Fix connector test * Switching feature flag to global variable * Removing this.config use * Fixing circular import and renaming flag
This commit is contained in:
parent
b9ef084130
commit
07f32d03b3
|
@ -5,8 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { DEFAULT_MAX_SIGNALS } from '../../security_solution/common/constants';
|
||||
|
||||
export const APP_ID = 'cases';
|
||||
|
||||
/**
|
||||
|
@ -53,5 +51,12 @@ export const SUPPORTED_CONNECTORS = [
|
|||
* Alerts
|
||||
*/
|
||||
|
||||
// this value is from x-pack/plugins/security_solution/common/constants.ts
|
||||
const DEFAULT_MAX_SIGNALS = 100;
|
||||
export const MAX_ALERTS_PER_SUB_CASE = 5000;
|
||||
export const MAX_GENERATED_ALERTS_PER_SUB_CASE = MAX_ALERTS_PER_SUB_CASE / DEFAULT_MAX_SIGNALS;
|
||||
|
||||
/**
|
||||
* This flag governs enabling the case as a connector feature. It is disabled by default as the feature is not complete.
|
||||
*/
|
||||
export const ENABLE_CASE_CONNECTOR = false;
|
||||
|
|
|
@ -35,6 +35,7 @@ import {
|
|||
CaseUserActionServiceSetup,
|
||||
} from '../../services';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
|
||||
|
||||
interface CreateCaseArgs {
|
||||
caseConfigureService: CaseConfigureServiceSetup;
|
||||
|
@ -60,9 +61,19 @@ export const create = async ({
|
|||
}: CreateCaseArgs): Promise<CaseResponse> => {
|
||||
// default to an individual case if the type is not defined.
|
||||
const { type = CaseType.individual, ...nonTypeCaseFields } = theCase;
|
||||
|
||||
if (!ENABLE_CASE_CONNECTOR && type === CaseType.collection) {
|
||||
throw Boom.badRequest(
|
||||
'Case type cannot be collection when the case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
|
||||
const query = pipe(
|
||||
// decode with the defaulted type field
|
||||
excess(CasesClientPostRequestRt).decode({ type, ...nonTypeCaseFields }),
|
||||
excess(CasesClientPostRequestRt).decode({
|
||||
type,
|
||||
...nonTypeCaseFields,
|
||||
}),
|
||||
fold(throwErrors(Boom.badRequest), identity)
|
||||
);
|
||||
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SavedObjectsClientContract, Logger } from 'kibana/server';
|
||||
import { SavedObjectsClientContract, Logger, SavedObject } from 'kibana/server';
|
||||
import { flattenCaseSavedObject } from '../../routes/api/utils';
|
||||
import { CaseResponseRt, CaseResponse } from '../../../common/api';
|
||||
import { CaseResponseRt, CaseResponse, ESCaseAttributes } from '../../../common/api';
|
||||
import { CaseServiceSetup } from '../../services';
|
||||
import { countAlertsForID } from '../../common';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
|
||||
|
||||
interface GetParams {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
|
@ -33,15 +34,26 @@ export const get = async ({
|
|||
includeSubCaseComments = false,
|
||||
}: GetParams): Promise<CaseResponse> => {
|
||||
try {
|
||||
const [theCase, subCasesForCaseId] = await Promise.all([
|
||||
caseService.getCase({
|
||||
let theCase: SavedObject<ESCaseAttributes>;
|
||||
let subCaseIds: string[] = [];
|
||||
|
||||
if (ENABLE_CASE_CONNECTOR) {
|
||||
const [caseInfo, subCasesForCaseId] = await Promise.all([
|
||||
caseService.getCase({
|
||||
client: savedObjectsClient,
|
||||
id,
|
||||
}),
|
||||
caseService.findSubCasesByCaseId({ client: savedObjectsClient, ids: [id] }),
|
||||
]);
|
||||
|
||||
theCase = caseInfo;
|
||||
subCaseIds = subCasesForCaseId.saved_objects.map((so) => so.id);
|
||||
} else {
|
||||
theCase = await caseService.getCase({
|
||||
client: savedObjectsClient,
|
||||
id,
|
||||
}),
|
||||
caseService.findSubCasesByCaseId({ client: savedObjectsClient, ids: [id] }),
|
||||
]);
|
||||
|
||||
const subCaseIds = subCasesForCaseId.saved_objects.map((so) => so.id);
|
||||
});
|
||||
}
|
||||
|
||||
if (!includeComments) {
|
||||
return CaseResponseRt.encode(
|
||||
|
@ -58,7 +70,7 @@ export const get = async ({
|
|||
sortField: 'created_at',
|
||||
sortOrder: 'asc',
|
||||
},
|
||||
includeSubCaseComments,
|
||||
includeSubCaseComments: ENABLE_CASE_CONNECTOR && includeSubCaseComments,
|
||||
});
|
||||
|
||||
return CaseResponseRt.encode(
|
||||
|
|
|
@ -40,6 +40,7 @@ import {
|
|||
} from '../../services';
|
||||
import { CasesClientHandler } from '../client';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
|
||||
|
||||
/**
|
||||
* Returns true if the case should be closed based on the configuration settings and whether the case
|
||||
|
@ -92,7 +93,11 @@ export const push = async ({
|
|||
|
||||
try {
|
||||
[theCase, connector, userActions] = await Promise.all([
|
||||
casesClient.get({ id: caseId, includeComments: true, includeSubCaseComments: true }),
|
||||
casesClient.get({
|
||||
id: caseId,
|
||||
includeComments: true,
|
||||
includeSubCaseComments: ENABLE_CASE_CONNECTOR,
|
||||
}),
|
||||
actionsClient.get({ id: connectorId }),
|
||||
casesClient.getUserActions({ caseId }),
|
||||
]);
|
||||
|
@ -183,7 +188,7 @@ export const push = async ({
|
|||
page: 1,
|
||||
perPage: theCase?.totalComment ?? 0,
|
||||
},
|
||||
includeSubCaseComments: true,
|
||||
includeSubCaseComments: ENABLE_CASE_CONNECTOR,
|
||||
}),
|
||||
]);
|
||||
} catch (e) {
|
||||
|
|
|
@ -55,6 +55,7 @@ import { CasesClientHandler } from '..';
|
|||
import { createAlertUpdateRequest } from '../../common';
|
||||
import { UpdateAlertRequest } from '../types';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
|
||||
|
||||
/**
|
||||
* Throws an error if any of the requests attempt to update a collection style cases' status field.
|
||||
|
@ -97,6 +98,22 @@ function throwIfUpdateTypeCollectionToIndividual(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error if any of the requests attempt to update the type of a case.
|
||||
*/
|
||||
function throwIfUpdateType(requests: ESCasePatchRequest[]) {
|
||||
const requestsUpdatingType = requests.filter((req) => req.type !== undefined);
|
||||
|
||||
if (requestsUpdatingType.length > 0) {
|
||||
const ids = requestsUpdatingType.map((req) => req.id);
|
||||
throw Boom.badRequest(
|
||||
`Updating the type of a case when sub cases are disabled is not allowed ids: [${ids.join(
|
||||
', '
|
||||
)}]`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error if any of the requests attempt to update an individual style cases' type field to a collection
|
||||
* when alerts are attached to the case.
|
||||
|
@ -396,6 +413,10 @@ export const update = async ({
|
|||
return acc;
|
||||
}, new Map<string, SavedObject<ESCaseAttributes>>());
|
||||
|
||||
if (!ENABLE_CASE_CONNECTOR) {
|
||||
throwIfUpdateType(updateFilterCases);
|
||||
}
|
||||
|
||||
throwIfUpdateStatusOfCollection(updateFilterCases, casesMap);
|
||||
throwIfUpdateTypeCollectionToIndividual(updateFilterCases, casesMap);
|
||||
await throwIfInvalidUpdateOfTypeWithAlerts({
|
||||
|
|
|
@ -36,7 +36,10 @@ import { CommentableCase, createAlertUpdateRequest } from '../../common';
|
|||
import { CasesClientHandler } from '..';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import { CASE_COMMENT_SAVED_OBJECT } from '../../saved_object_types';
|
||||
import { MAX_GENERATED_ALERTS_PER_SUB_CASE } from '../../../common/constants';
|
||||
import {
|
||||
ENABLE_CASE_CONNECTOR,
|
||||
MAX_GENERATED_ALERTS_PER_SUB_CASE,
|
||||
} from '../../../common/constants';
|
||||
|
||||
async function getSubCase({
|
||||
caseService,
|
||||
|
@ -224,10 +227,14 @@ async function getCombinedCase({
|
|||
client,
|
||||
id,
|
||||
}),
|
||||
service.getSubCase({
|
||||
client,
|
||||
id,
|
||||
}),
|
||||
...(ENABLE_CASE_CONNECTOR
|
||||
? [
|
||||
service.getSubCase({
|
||||
client,
|
||||
id,
|
||||
}),
|
||||
]
|
||||
: [Promise.reject('case connector feature is disabled')]),
|
||||
]);
|
||||
|
||||
if (subCasePromise.status === 'fulfilled') {
|
||||
|
@ -287,6 +294,12 @@ export const addComment = async ({
|
|||
);
|
||||
|
||||
if (isCommentRequestTypeGenAlert(comment)) {
|
||||
if (!ENABLE_CASE_CONNECTOR) {
|
||||
throw Boom.badRequest(
|
||||
'Attempting to add a generated alert when case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
|
||||
return addGeneratedAlerts({
|
||||
caseId,
|
||||
comment,
|
||||
|
|
|
@ -886,7 +886,34 @@ describe('case connector', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('execute', () => {
|
||||
it('should throw an error when executing the connector', async () => {
|
||||
expect.assertions(2);
|
||||
const actionId = 'some-id';
|
||||
const params: CaseExecutorParams = {
|
||||
// @ts-expect-error
|
||||
subAction: 'not-supported',
|
||||
// @ts-expect-error
|
||||
subActionParams: {},
|
||||
};
|
||||
|
||||
const executorOptions: CaseActionTypeExecutorOptions = {
|
||||
actionId,
|
||||
config: {},
|
||||
params,
|
||||
secrets: {},
|
||||
services,
|
||||
};
|
||||
|
||||
try {
|
||||
await caseActionType.executor(executorOptions);
|
||||
} catch (e) {
|
||||
expect(e).not.toBeNull();
|
||||
expect(e.message).toBe('[Action][Case] connector not supported');
|
||||
}
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: enable these tests after the case connector feature is completed
|
||||
describe.skip('execute', () => {
|
||||
it('allows only supported sub-actions', async () => {
|
||||
expect.assertions(2);
|
||||
const actionId = 'some-id';
|
||||
|
|
|
@ -27,6 +27,7 @@ import * as i18n from './translations';
|
|||
import { GetActionTypeParams, isCommentGeneratedAlert, separator } from '..';
|
||||
import { nullUser } from '../../common';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
|
||||
|
||||
const supportedSubActions: string[] = ['create', 'update', 'addComment'];
|
||||
|
||||
|
@ -70,6 +71,12 @@ async function executor(
|
|||
}: GetActionTypeParams,
|
||||
execOptions: CaseActionTypeExecutorOptions
|
||||
): Promise<ActionTypeExecutorResult<CaseExecutorResponse | {}>> {
|
||||
if (!ENABLE_CASE_CONNECTOR) {
|
||||
const msg = '[Action][Case] connector not supported';
|
||||
logger.error(msg);
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
const { actionId, params, services } = execOptions;
|
||||
const { subAction, subActionParams } = params;
|
||||
let data: CaseExecutorResponse | null = null;
|
||||
|
|
|
@ -10,7 +10,7 @@ import { CoreSetup, CoreStart } from 'src/core/server';
|
|||
|
||||
import { SecurityPluginSetup } from '../../security/server';
|
||||
import { PluginSetupContract as ActionsPluginSetup } from '../../actions/server';
|
||||
import { APP_ID } from '../common/constants';
|
||||
import { APP_ID, ENABLE_CASE_CONNECTOR } from '../common/constants';
|
||||
|
||||
import { ConfigType } from './config';
|
||||
import { initCaseApi } from './routes/api';
|
||||
|
@ -70,7 +70,6 @@ export class CasePlugin {
|
|||
core.savedObjects.registerType(caseConfigureSavedObjectType);
|
||||
core.savedObjects.registerType(caseConnectorMappingsSavedObjectType);
|
||||
core.savedObjects.registerType(caseSavedObjectType);
|
||||
core.savedObjects.registerType(subCaseSavedObjectType);
|
||||
core.savedObjects.registerType(caseUserActionSavedObjectType);
|
||||
|
||||
this.log.debug(
|
||||
|
@ -111,15 +110,18 @@ export class CasePlugin {
|
|||
router,
|
||||
});
|
||||
|
||||
registerConnectors({
|
||||
actionsRegisterType: plugins.actions.registerType,
|
||||
logger: this.log,
|
||||
caseService: this.caseService,
|
||||
caseConfigureService: this.caseConfigureService,
|
||||
connectorMappingsService: this.connectorMappingsService,
|
||||
userActionService: this.userActionService,
|
||||
alertsService: this.alertsService,
|
||||
});
|
||||
if (ENABLE_CASE_CONNECTOR) {
|
||||
core.savedObjects.registerType(subCaseSavedObjectType);
|
||||
registerConnectors({
|
||||
actionsRegisterType: plugins.actions.registerType,
|
||||
logger: this.log,
|
||||
caseService: this.caseService,
|
||||
caseConfigureService: this.caseConfigureService,
|
||||
connectorMappingsService: this.connectorMappingsService,
|
||||
userActionService: this.userActionService,
|
||||
alertsService: this.alertsService,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public start(core: CoreStart) {
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import Boom from '@hapi/boom';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers';
|
||||
import { RouteDeps } from '../../types';
|
||||
import { wrapError } from '../../utils';
|
||||
import { CASE_COMMENTS_URL } from '../../../../../common/constants';
|
||||
import { CASE_COMMENTS_URL, ENABLE_CASE_CONNECTOR } from '../../../../../common/constants';
|
||||
import { AssociationType } from '../../../../../common/api';
|
||||
|
||||
export function initDeleteAllCommentsApi({
|
||||
|
@ -35,18 +35,23 @@ export function initDeleteAllCommentsApi({
|
|||
},
|
||||
async (context, request, response) => {
|
||||
try {
|
||||
if (!ENABLE_CASE_CONNECTOR && request.query?.subCaseId !== undefined) {
|
||||
throw Boom.badRequest(
|
||||
'The `subCaseId` is not supported when the case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
|
||||
const client = context.core.savedObjects.client;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { username, full_name, email } = await caseService.getUser({ request });
|
||||
const deleteDate = new Date().toISOString();
|
||||
|
||||
const id = request.query?.subCaseId ?? request.params.case_id;
|
||||
const subCaseId = request.query?.subCaseId;
|
||||
const id = subCaseId ?? request.params.case_id;
|
||||
const comments = await caseService.getCommentsByAssociation({
|
||||
client,
|
||||
id,
|
||||
associationType: request.query?.subCaseId
|
||||
? AssociationType.subCase
|
||||
: AssociationType.case,
|
||||
associationType: subCaseId ? AssociationType.subCase : AssociationType.case,
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
|
@ -66,7 +71,7 @@ export function initDeleteAllCommentsApi({
|
|||
actionAt: deleteDate,
|
||||
actionBy: { username, full_name, email },
|
||||
caseId: request.params.case_id,
|
||||
subCaseId: request.query?.subCaseId,
|
||||
subCaseId,
|
||||
commentId: comment.id,
|
||||
fields: ['comment'],
|
||||
})
|
||||
|
|
|
@ -12,7 +12,7 @@ import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../../saved_obje
|
|||
import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers';
|
||||
import { RouteDeps } from '../../types';
|
||||
import { wrapError } from '../../utils';
|
||||
import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants';
|
||||
import { CASE_COMMENT_DETAILS_URL, ENABLE_CASE_CONNECTOR } from '../../../../../common/constants';
|
||||
|
||||
export function initDeleteCommentApi({
|
||||
caseService,
|
||||
|
@ -37,6 +37,12 @@ export function initDeleteCommentApi({
|
|||
},
|
||||
async (context, request, response) => {
|
||||
try {
|
||||
if (!ENABLE_CASE_CONNECTOR && request.query?.subCaseId !== undefined) {
|
||||
throw Boom.badRequest(
|
||||
'The `subCaseId` is not supported when the case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
|
||||
const client = context.core.savedObjects.client;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { username, full_name, email } = await caseService.getUser({ request });
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
} from '../../../../../common/api';
|
||||
import { RouteDeps } from '../../types';
|
||||
import { escapeHatch, transformComments, wrapError } from '../../utils';
|
||||
import { CASE_COMMENTS_URL } from '../../../../../common/constants';
|
||||
import { CASE_COMMENTS_URL, ENABLE_CASE_CONNECTOR } from '../../../../../common/constants';
|
||||
import { defaultPage, defaultPerPage } from '../..';
|
||||
|
||||
const FindQueryParamsRt = rt.partial({
|
||||
|
@ -49,6 +49,12 @@ export function initFindCaseCommentsApi({ caseService, router, logger }: RouteDe
|
|||
fold(throwErrors(Boom.badRequest), identity)
|
||||
);
|
||||
|
||||
if (!ENABLE_CASE_CONNECTOR && query.subCaseId !== undefined) {
|
||||
throw Boom.badRequest(
|
||||
'The `subCaseId` is not supported when the case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
|
||||
const id = query.subCaseId ?? request.params.case_id;
|
||||
const associationType = query.subCaseId ? AssociationType.subCase : AssociationType.case;
|
||||
const args = query
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import Boom from '@hapi/boom';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { SavedObjectsFindResponse } from 'kibana/server';
|
||||
import { AllCommentsResponseRt, CommentAttributes } from '../../../../../common/api';
|
||||
import { RouteDeps } from '../../types';
|
||||
import { flattenCommentSavedObjects, wrapError } from '../../utils';
|
||||
import { CASE_COMMENTS_URL } from '../../../../../common/constants';
|
||||
import { CASE_COMMENTS_URL, ENABLE_CASE_CONNECTOR } from '../../../../../common/constants';
|
||||
import { defaultSortField } from '../../../../common';
|
||||
|
||||
export function initGetAllCommentsApi({ caseService, router, logger }: RouteDeps) {
|
||||
|
@ -35,6 +36,16 @@ export function initGetAllCommentsApi({ caseService, router, logger }: RouteDeps
|
|||
const client = context.core.savedObjects.client;
|
||||
let comments: SavedObjectsFindResponse<CommentAttributes>;
|
||||
|
||||
if (
|
||||
!ENABLE_CASE_CONNECTOR &&
|
||||
(request.query?.subCaseId !== undefined ||
|
||||
request.query?.includeSubCaseComments !== undefined)
|
||||
) {
|
||||
throw Boom.badRequest(
|
||||
'The `subCaseId` and `includeSubCaseComments` are not supported when the case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
|
||||
if (request.query?.subCaseId) {
|
||||
comments = await caseService.getAllSubCaseComments({
|
||||
client,
|
||||
|
|
|
@ -19,7 +19,7 @@ import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../../saved_obje
|
|||
import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers';
|
||||
import { RouteDeps } from '../../types';
|
||||
import { escapeHatch, wrapError, decodeCommentRequest } from '../../utils';
|
||||
import { CASE_COMMENTS_URL } from '../../../../../common/constants';
|
||||
import { CASE_COMMENTS_URL, ENABLE_CASE_CONNECTOR } from '../../../../../common/constants';
|
||||
import { CaseServiceSetup } from '../../../../services';
|
||||
|
||||
interface CombinedCaseParams {
|
||||
|
@ -82,6 +82,12 @@ export function initPatchCommentApi({ caseService, router, userActionService, lo
|
|||
},
|
||||
async (context, request, response) => {
|
||||
try {
|
||||
if (!ENABLE_CASE_CONNECTOR && request.query?.subCaseId !== undefined) {
|
||||
throw Boom.badRequest(
|
||||
'The `subCaseId` is not supported when the case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
|
||||
const client = context.core.savedObjects.client;
|
||||
const query = pipe(
|
||||
CommentPatchRequestRt.decode(request.body),
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import Boom from '@hapi/boom';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { escapeHatch, wrapError } from '../../utils';
|
||||
import { RouteDeps } from '../../types';
|
||||
import { CASE_COMMENTS_URL } from '../../../../../common/constants';
|
||||
import { CASE_COMMENTS_URL, ENABLE_CASE_CONNECTOR } from '../../../../../common/constants';
|
||||
import { CommentRequest } from '../../../../../common/api';
|
||||
|
||||
export function initPostCommentApi({ router, logger }: RouteDeps) {
|
||||
|
@ -28,15 +29,21 @@ export function initPostCommentApi({ router, logger }: RouteDeps) {
|
|||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
if (!context.cases) {
|
||||
return response.badRequest({ body: 'RouteHandlerContext is not registered for cases' });
|
||||
}
|
||||
|
||||
const casesClient = context.cases.getCasesClient();
|
||||
const caseId = request.query?.subCaseId ?? request.params.case_id;
|
||||
const comment = request.body as CommentRequest;
|
||||
|
||||
try {
|
||||
if (!ENABLE_CASE_CONNECTOR && request.query?.subCaseId !== undefined) {
|
||||
throw Boom.badRequest(
|
||||
'The `subCaseId` is not supported when the case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
|
||||
if (!context.cases) {
|
||||
return response.badRequest({ body: 'RouteHandlerContext is not registered for cases' });
|
||||
}
|
||||
|
||||
const casesClient = context.cases.getCasesClient();
|
||||
const caseId = request.query?.subCaseId ?? request.params.case_id;
|
||||
const comment = request.body as CommentRequest;
|
||||
|
||||
return response.ok({
|
||||
body: await casesClient.addComment({ caseId, comment }),
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ import { SavedObjectsClientContract } from 'src/core/server';
|
|||
import { buildCaseUserActionItem } from '../../../services/user_actions/helpers';
|
||||
import { RouteDeps } from '../types';
|
||||
import { wrapError } from '../utils';
|
||||
import { CASES_URL } from '../../../../common/constants';
|
||||
import { CASES_URL, ENABLE_CASE_CONNECTOR } from '../../../../common/constants';
|
||||
import { CaseServiceSetup } from '../../../services';
|
||||
|
||||
async function deleteSubCases({
|
||||
|
@ -91,7 +91,10 @@ export function initDeleteCasesApi({ caseService, router, userActionService, log
|
|||
);
|
||||
}
|
||||
|
||||
await deleteSubCases({ caseService, client, caseIds: request.query.ids });
|
||||
if (ENABLE_CASE_CONNECTOR) {
|
||||
await deleteSubCases({ caseService, client, caseIds: request.query.ids });
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { username, full_name, email } = await caseService.getUser({ request });
|
||||
const deleteDate = new Date().toISOString();
|
||||
|
@ -104,7 +107,14 @@ export function initDeleteCasesApi({ caseService, router, userActionService, log
|
|||
actionAt: deleteDate,
|
||||
actionBy: { username, full_name, email },
|
||||
caseId: id,
|
||||
fields: ['comment', 'description', 'status', 'tags', 'title', 'sub_case'],
|
||||
fields: [
|
||||
'comment',
|
||||
'description',
|
||||
'status',
|
||||
'tags',
|
||||
'title',
|
||||
...(ENABLE_CASE_CONNECTOR ? ['sub_case'] : []),
|
||||
],
|
||||
})
|
||||
),
|
||||
});
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import Boom from '@hapi/boom';
|
||||
import { RouteDeps } from '../types';
|
||||
import { wrapError } from '../utils';
|
||||
import { CASE_DETAILS_URL } from '../../../../common/constants';
|
||||
import { CASE_DETAILS_URL, ENABLE_CASE_CONNECTOR } from '../../../../common/constants';
|
||||
|
||||
export function initGetCaseApi({ router, logger }: RouteDeps) {
|
||||
router.get(
|
||||
|
@ -27,6 +28,11 @@ export function initGetCaseApi({ router, logger }: RouteDeps) {
|
|||
},
|
||||
async (context, request, response) => {
|
||||
try {
|
||||
if (!ENABLE_CASE_CONNECTOR && request.query.includeSubCaseComments !== undefined) {
|
||||
throw Boom.badRequest(
|
||||
'The `subCaseId` is not supported when the case connector feature is disabled'
|
||||
);
|
||||
}
|
||||
const casesClient = context.cases.getCasesClient();
|
||||
const id = request.params.case_id;
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import { initGetSubCaseApi } from './cases/sub_case/get_sub_case';
|
|||
import { initPatchSubCasesApi } from './cases/sub_case/patch_sub_cases';
|
||||
import { initFindSubCasesApi } from './cases/sub_case/find_sub_cases';
|
||||
import { initDeleteSubCasesApi } from './cases/sub_case/delete_sub_cases';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
|
||||
|
||||
/**
|
||||
* Default page number when interacting with the saved objects API.
|
||||
|
@ -56,12 +57,16 @@ export function initCaseApi(deps: RouteDeps) {
|
|||
initPostCaseApi(deps);
|
||||
initPushCaseApi(deps);
|
||||
initGetAllCaseUserActionsApi(deps);
|
||||
initGetAllSubCaseUserActionsApi(deps);
|
||||
// Sub cases
|
||||
initGetSubCaseApi(deps);
|
||||
initPatchSubCasesApi(deps);
|
||||
initFindSubCasesApi(deps);
|
||||
initDeleteSubCasesApi(deps);
|
||||
|
||||
if (ENABLE_CASE_CONNECTOR) {
|
||||
// Sub cases
|
||||
initGetAllSubCaseUserActionsApi(deps);
|
||||
initGetSubCaseApi(deps);
|
||||
initPatchSubCasesApi(deps);
|
||||
initFindSubCasesApi(deps);
|
||||
initDeleteSubCasesApi(deps);
|
||||
}
|
||||
|
||||
// Comments
|
||||
initDeleteCommentApi(deps);
|
||||
initDeleteAllCommentsApi(deps);
|
||||
|
|
|
@ -34,6 +34,7 @@ import {
|
|||
caseTypeField,
|
||||
CasesFindRequest,
|
||||
} from '../../common/api';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../common/constants';
|
||||
import { combineFilters, defaultSortField, groupTotalAlertsByID } from '../common';
|
||||
import { defaultPage, defaultPerPage } from '../routes/api';
|
||||
import {
|
||||
|
@ -282,13 +283,15 @@ export class CaseService implements CaseServiceSetup {
|
|||
options: caseOptions,
|
||||
});
|
||||
|
||||
const subCasesResp = await this.findSubCasesGroupByCase({
|
||||
client,
|
||||
options: subCaseOptions,
|
||||
ids: cases.saved_objects
|
||||
.filter((caseInfo) => caseInfo.attributes.type === CaseType.collection)
|
||||
.map((caseInfo) => caseInfo.id),
|
||||
});
|
||||
const subCasesResp = ENABLE_CASE_CONNECTOR
|
||||
? await this.findSubCasesGroupByCase({
|
||||
client,
|
||||
options: subCaseOptions,
|
||||
ids: cases.saved_objects
|
||||
.filter((caseInfo) => caseInfo.attributes.type === CaseType.collection)
|
||||
.map((caseInfo) => caseInfo.id),
|
||||
})
|
||||
: { subCasesMap: new Map<string, SubCaseResponse[]>(), page: 0, perPage: 0 };
|
||||
|
||||
const casesMap = cases.saved_objects.reduce((accMap, caseInfo) => {
|
||||
const subCasesForCase = subCasesResp.subCasesMap.get(caseInfo.id);
|
||||
|
@ -407,7 +410,7 @@ export class CaseService implements CaseServiceSetup {
|
|||
|
||||
let subCasesTotal = 0;
|
||||
|
||||
if (subCaseOptions) {
|
||||
if (ENABLE_CASE_CONNECTOR && subCaseOptions) {
|
||||
subCasesTotal = await this.findSubCaseStatusStats({
|
||||
client,
|
||||
options: subCaseOptions,
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../cases/common/constants';
|
||||
|
||||
export const APP_ID = 'securitySolution';
|
||||
export const SERVER_APP_ID = 'siem';
|
||||
export const APP_NAME = 'Security';
|
||||
|
@ -171,7 +173,6 @@ export const ML_GROUP_IDS = [ML_GROUP_ID, LEGACY_ML_GROUP_ID];
|
|||
/*
|
||||
Rule notifications options
|
||||
*/
|
||||
export const ENABLE_CASE_CONNECTOR = true;
|
||||
export const NOTIFICATION_SUPPORTED_ACTION_TYPES_IDS = [
|
||||
'.email',
|
||||
'.slack',
|
||||
|
|
|
@ -94,7 +94,26 @@ describe('RuleActionsField', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it('if we do NOT have an error on case action creation, we are supporting case connector', () => {
|
||||
// sub-cases-enabled: remove this once the sub cases and connector feature is completed
|
||||
// https://github.com/elastic/kibana/issues/94115
|
||||
it('should not contain the case connector as a supported action', () => {
|
||||
expect(getSupportedActions(actions, false)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"enabled": true,
|
||||
"enabledInConfig": false,
|
||||
"enabledInLicense": true,
|
||||
"id": ".jira",
|
||||
"minimumLicenseRequired": "gold",
|
||||
"name": "My Jira",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
// sub-cases-enabled: unskip after sub cases and the case connector is supported
|
||||
// https://github.com/elastic/kibana/issues/94115
|
||||
it.skip('if we do NOT have an error on case action creation, we are supporting case connector', () => {
|
||||
expect(getSupportedActions(actions, false)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
|
|
|
@ -85,7 +85,28 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(404);
|
||||
});
|
||||
|
||||
describe('sub case comments', () => {
|
||||
it('should return a 400 when attempting to delete all comments when passing the `subCaseId` parameter', async () => {
|
||||
const { body } = await supertest
|
||||
.delete(`${CASES_URL}/case-id/comments?subCaseId=value`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(400);
|
||||
// make sure the failure is because of the subCaseId
|
||||
expect(body.message).to.contain('subCaseId');
|
||||
});
|
||||
|
||||
it('should return a 400 when attempting to delete a single comment when passing the `subCaseId` parameter', async () => {
|
||||
const { body } = await supertest
|
||||
.delete(`${CASES_URL}/case-id/comments/comment-id?subCaseId=value`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(400);
|
||||
// make sure the failure is because of the subCaseId
|
||||
expect(body.message).to.contain('subCaseId');
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('sub case comments', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
|
|
|
@ -111,7 +111,18 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(400);
|
||||
});
|
||||
|
||||
describe('sub case comments', () => {
|
||||
it('should return a 400 when passing the subCaseId parameter', async () => {
|
||||
const { body } = await supertest
|
||||
.get(`${CASES_URL}/case-id/comments/_find?search=unique&subCaseId=value`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(400);
|
||||
|
||||
expect(body.message).to.contain('subCaseId');
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('sub case comments', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
|
|
|
@ -24,13 +24,6 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
const es = getService('es');
|
||||
|
||||
describe('get_all_comments', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteAllCaseItems(es);
|
||||
});
|
||||
|
@ -63,47 +56,78 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
expect(comments.length).to.eql(2);
|
||||
});
|
||||
|
||||
it('should get comments from a case and its sub cases', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
await supertest
|
||||
.post(`${CASES_URL}/${caseInfo.id}/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCommentUserReq)
|
||||
.expect(200);
|
||||
|
||||
const { body: comments } = await supertest
|
||||
.get(`${CASES_URL}/${caseInfo.id}/comments?includeSubCaseComments=true`)
|
||||
.expect(200);
|
||||
|
||||
expect(comments.length).to.eql(2);
|
||||
expect(comments[0].type).to.eql(CommentType.generatedAlert);
|
||||
expect(comments[1].type).to.eql(CommentType.user);
|
||||
});
|
||||
|
||||
it('should get comments from a sub cases', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
await supertest
|
||||
.post(`${CASES_URL}/${caseInfo.subCases![0].id}/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCommentUserReq)
|
||||
.expect(200);
|
||||
|
||||
const { body: comments } = await supertest
|
||||
.get(`${CASES_URL}/${caseInfo.id}/comments?subCaseId=${caseInfo.subCases![0].id}`)
|
||||
.expect(200);
|
||||
|
||||
expect(comments.length).to.eql(2);
|
||||
expect(comments[0].type).to.eql(CommentType.generatedAlert);
|
||||
expect(comments[1].type).to.eql(CommentType.user);
|
||||
});
|
||||
|
||||
it('should not find any comments for an invalid case id', async () => {
|
||||
it('should return a 400 when passing the subCaseId parameter', async () => {
|
||||
const { body } = await supertest
|
||||
.get(`${CASES_URL}/fake-id/comments`)
|
||||
.get(`${CASES_URL}/case-id/comments?subCaseId=value`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
expect(body.length).to.eql(0);
|
||||
.expect(400);
|
||||
|
||||
expect(body.message).to.contain('subCaseId');
|
||||
});
|
||||
|
||||
it('should return a 400 when passing the includeSubCaseComments parameter', async () => {
|
||||
const { body } = await supertest
|
||||
.get(`${CASES_URL}/case-id/comments?includeSubCaseComments=true`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(400);
|
||||
|
||||
expect(body.message).to.contain('includeSubCaseComments');
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('sub cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
|
||||
it('should get comments from a case and its sub cases', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
await supertest
|
||||
.post(`${CASES_URL}/${caseInfo.id}/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCommentUserReq)
|
||||
.expect(200);
|
||||
|
||||
const { body: comments } = await supertest
|
||||
.get(`${CASES_URL}/${caseInfo.id}/comments?includeSubCaseComments=true`)
|
||||
.expect(200);
|
||||
|
||||
expect(comments.length).to.eql(2);
|
||||
expect(comments[0].type).to.eql(CommentType.generatedAlert);
|
||||
expect(comments[1].type).to.eql(CommentType.user);
|
||||
});
|
||||
|
||||
it('should get comments from a sub cases', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
await supertest
|
||||
.post(`${CASES_URL}/${caseInfo.subCases![0].id}/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCommentUserReq)
|
||||
.expect(200);
|
||||
|
||||
const { body: comments } = await supertest
|
||||
.get(`${CASES_URL}/${caseInfo.id}/comments?subCaseId=${caseInfo.subCases![0].id}`)
|
||||
.expect(200);
|
||||
|
||||
expect(comments.length).to.eql(2);
|
||||
expect(comments[0].type).to.eql(CommentType.generatedAlert);
|
||||
expect(comments[1].type).to.eql(CommentType.user);
|
||||
});
|
||||
|
||||
it('should not find any comments for an invalid case id', async () => {
|
||||
const { body } = await supertest
|
||||
.get(`${CASES_URL}/fake-id/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
expect(body.length).to.eql(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -24,13 +24,6 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
const es = getService('es');
|
||||
|
||||
describe('get_comment', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteAllCaseItems(es);
|
||||
});
|
||||
|
@ -57,14 +50,6 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
expect(comment).to.eql(patchedCase.comments[0]);
|
||||
});
|
||||
|
||||
it('should get a sub case comment', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
const { body: comment }: { body: CommentResponse } = await supertest
|
||||
.get(`${CASES_URL}/${caseInfo.id}/comments/${caseInfo.comments![0].id}`)
|
||||
.expect(200);
|
||||
expect(comment.type).to.be(CommentType.generatedAlert);
|
||||
});
|
||||
|
||||
it('unhappy path - 404s when comment is not there', async () => {
|
||||
await supertest
|
||||
.get(`${CASES_URL}/fake-id/comments/fake-comment`)
|
||||
|
@ -72,5 +57,23 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.send()
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('sub cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
it('should get a sub case comment', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
const { body: comment }: { body: CommentResponse } = await supertest
|
||||
.get(`${CASES_URL}/${caseInfo.id}/comments/${caseInfo.comments![0].id}`)
|
||||
.expect(200);
|
||||
expect(comment.type).to.be(CommentType.generatedAlert);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -39,7 +39,28 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
await deleteCasesUserActions(es);
|
||||
});
|
||||
|
||||
describe('sub case comments', () => {
|
||||
it('should return a 400 when the subCaseId parameter is passed', async () => {
|
||||
const { body } = await supertest
|
||||
.patch(`${CASES_URL}/case-id}/comments?subCaseId=value`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
id: 'id',
|
||||
version: 'version',
|
||||
type: CommentType.alert,
|
||||
alertId: 'test-id',
|
||||
index: 'test-index',
|
||||
rule: {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
},
|
||||
})
|
||||
.expect(400);
|
||||
|
||||
expect(body.message).to.contain('subCaseId');
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('sub case comments', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
|
|
|
@ -227,7 +227,8 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(400);
|
||||
});
|
||||
|
||||
it('400s when adding an alert to a collection case', async () => {
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
it.skip('400s when adding an alert to a collection case', async () => {
|
||||
const { body: postedCase } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
|
@ -376,7 +377,17 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('sub case comments', () => {
|
||||
it('should return a 400 when passing the subCaseId', async () => {
|
||||
const { body } = await supertest
|
||||
.post(`${CASES_URL}/case-id/comments?subCaseId=value`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCommentUserReq)
|
||||
.expect(400);
|
||||
expect(body.message).to.contain('subCaseId');
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('sub case comments', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
|
|
|
@ -90,7 +90,8 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(404);
|
||||
});
|
||||
|
||||
describe('sub cases', () => {
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('sub cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
|
|
|
@ -248,7 +248,8 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
expect(body.count_in_progress_cases).to.eql(1);
|
||||
});
|
||||
|
||||
describe('stats with sub cases', () => {
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('stats with sub cases', () => {
|
||||
let collection: CreateSubCaseResp;
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
|
|
|
@ -43,6 +43,16 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
expect(data).to.eql(postCaseResp(postedCase.id));
|
||||
});
|
||||
|
||||
it('should return a 400 when passing the includeSubCaseComments', async () => {
|
||||
const { body } = await supertest
|
||||
.get(`${CASES_URL}/case-id?includeSubCaseComments=true`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(400);
|
||||
|
||||
expect(body.message).to.contain('subCaseId');
|
||||
});
|
||||
|
||||
it('unhappy path - 404s when case is not there', async () => {
|
||||
await supertest.get(`${CASES_URL}/fake-id`).set('kbn-xsrf', 'true').send().expect(404);
|
||||
});
|
||||
|
|
|
@ -134,7 +134,8 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(404);
|
||||
});
|
||||
|
||||
it('should 400 and not allow converting a collection back to an individual case', async () => {
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
it.skip('should 400 and not allow converting a collection back to an individual case', async () => {
|
||||
const { body: postedCase } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
|
@ -156,7 +157,8 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(400);
|
||||
});
|
||||
|
||||
it('should allow converting an individual case to a collection when it does not have alerts', async () => {
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
it.skip('should allow converting an individual case to a collection when it does not have alerts', async () => {
|
||||
const { body: postedCase } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
|
@ -212,7 +214,30 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(400);
|
||||
});
|
||||
|
||||
it("should 400 when attempting to update a collection case's status", async () => {
|
||||
it('should 400 when attempting to update the case type when the case connector feature is disabled', async () => {
|
||||
const { body: postedCase } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCaseReq)
|
||||
.expect(200);
|
||||
|
||||
await supertest
|
||||
.patch(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
cases: [
|
||||
{
|
||||
id: postedCase.id,
|
||||
version: postedCase.version,
|
||||
type: CaseType.collection,
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(400);
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
it.skip("should 400 when attempting to update a collection case's status", async () => {
|
||||
const { body: postedCase } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
|
|
|
@ -234,7 +234,8 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
expect(body.status).to.eql('closed');
|
||||
});
|
||||
|
||||
it('should push a collection case but not close it when closure_type: close-by-pushing', async () => {
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
it.skip('should push a collection case but not close it when closure_type: close-by-pushing', async () => {
|
||||
const { body: connector } = await supertest
|
||||
.post('/api/actions/action')
|
||||
.set('kbn-xsrf', 'true')
|
||||
|
|
|
@ -26,75 +26,87 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const supertest = getService('supertest');
|
||||
const es = getService('es');
|
||||
|
||||
describe('delete_sub_cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteAllCaseItems(es);
|
||||
});
|
||||
|
||||
it('should delete a sub case', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
expect(caseInfo.subCases![0].id).to.not.eql(undefined);
|
||||
|
||||
const { body: subCase } = await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(subCase.id).to.not.eql(undefined);
|
||||
|
||||
const { body } = await supertest
|
||||
.delete(`${SUB_CASES_PATCH_DEL_URL}?ids=["${subCase.id}"]`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(204);
|
||||
|
||||
expect(body).to.eql({});
|
||||
// ENABLE_CASE_CONNECTOR: remove this outer describe once the case connector feature is completed
|
||||
describe('delete_sub_cases disabled routes', () => {
|
||||
it('should return a 404 when attempting to access the route and the case connector feature is disabled', async () => {
|
||||
await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.delete(`${SUB_CASES_PATCH_DEL_URL}?ids=["sub-case-id"]`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it(`should delete a sub case's comments when that case gets deleted`, async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
expect(caseInfo.subCases![0].id).to.not.eql(undefined);
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('delete_sub_cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteAllCaseItems(es);
|
||||
});
|
||||
|
||||
// there should be two comments on the sub case now
|
||||
const { body: patchedCaseWithSubCase }: { body: CaseResponse } = await supertest
|
||||
.post(`${CASES_URL}/${caseInfo.id}/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.query({ subCaseId: caseInfo.subCases![0].id })
|
||||
.send(postCommentUserReq)
|
||||
.expect(200);
|
||||
it('should delete a sub case', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
expect(caseInfo.subCases![0].id).to.not.eql(undefined);
|
||||
|
||||
const subCaseCommentUrl = `${CASES_URL}/${patchedCaseWithSubCase.id}/comments/${
|
||||
patchedCaseWithSubCase.comments![1].id
|
||||
}`;
|
||||
// make sure we can get the second comment
|
||||
await supertest.get(subCaseCommentUrl).set('kbn-xsrf', 'true').send().expect(200);
|
||||
const { body: subCase } = await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertest
|
||||
.delete(`${SUB_CASES_PATCH_DEL_URL}?ids=["${patchedCaseWithSubCase.subCases![0].id}"]`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(204);
|
||||
expect(subCase.id).to.not.eql(undefined);
|
||||
|
||||
await supertest.get(subCaseCommentUrl).set('kbn-xsrf', 'true').send().expect(404);
|
||||
});
|
||||
const { body } = await supertest
|
||||
.delete(`${SUB_CASES_PATCH_DEL_URL}?ids=["${subCase.id}"]`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(204);
|
||||
|
||||
it('unhappy path - 404s when sub case id is invalid', async () => {
|
||||
await supertest
|
||||
.delete(`${SUB_CASES_PATCH_DEL_URL}?ids=["fake-id"]`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(404);
|
||||
expect(body).to.eql({});
|
||||
await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.send()
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it(`should delete a sub case's comments when that case gets deleted`, async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
expect(caseInfo.subCases![0].id).to.not.eql(undefined);
|
||||
|
||||
// there should be two comments on the sub case now
|
||||
const { body: patchedCaseWithSubCase }: { body: CaseResponse } = await supertest
|
||||
.post(`${CASES_URL}/${caseInfo.id}/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.query({ subCaseId: caseInfo.subCases![0].id })
|
||||
.send(postCommentUserReq)
|
||||
.expect(200);
|
||||
|
||||
const subCaseCommentUrl = `${CASES_URL}/${patchedCaseWithSubCase.id}/comments/${
|
||||
patchedCaseWithSubCase.comments![1].id
|
||||
}`;
|
||||
// make sure we can get the second comment
|
||||
await supertest.get(subCaseCommentUrl).set('kbn-xsrf', 'true').send().expect(200);
|
||||
|
||||
await supertest
|
||||
.delete(`${SUB_CASES_PATCH_DEL_URL}?ids=["${patchedCaseWithSubCase.subCases![0].id}"]`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(204);
|
||||
|
||||
await supertest.get(subCaseCommentUrl).set('kbn-xsrf', 'true').send().expect(404);
|
||||
});
|
||||
|
||||
it('unhappy path - 404s when sub case id is invalid', async () => {
|
||||
await supertest
|
||||
.delete(`${SUB_CASES_PATCH_DEL_URL}?ids=["fake-id"]`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,226 +29,234 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
const supertest = getService('supertest');
|
||||
const es = getService('es');
|
||||
|
||||
describe('find_sub_cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteAllCaseItems(es);
|
||||
// ENABLE_CASE_CONNECTOR: remove this outer describe once the case connector feature is completed
|
||||
describe('find_sub_cases disabled route', () => {
|
||||
it('should return a 404 when attempting to access the route and the case connector feature is disabled', async () => {
|
||||
await supertest.get(`${getSubCasesUrl('case-id')}/_find`).expect(404);
|
||||
});
|
||||
|
||||
it('should not find any sub cases when none exist', async () => {
|
||||
const { body: caseResp }: { body: CaseResponse } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCollectionReq)
|
||||
.expect(200);
|
||||
|
||||
const { body: findSubCases } = await supertest
|
||||
.get(`${getSubCasesUrl(caseResp.id)}/_find`)
|
||||
.expect(200);
|
||||
|
||||
expect(findSubCases).to.eql({
|
||||
page: 1,
|
||||
per_page: 20,
|
||||
total: 0,
|
||||
subCases: [],
|
||||
count_open_cases: 0,
|
||||
count_closed_cases: 0,
|
||||
count_in_progress_cases: 0,
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('find_sub_cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a sub cases with comment stats', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find`)
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql({
|
||||
...findSubCasesResp,
|
||||
total: 1,
|
||||
// find should not return the comments themselves only the stats
|
||||
subCases: [{ ...caseInfo.subCases![0], comments: [], totalComment: 1, totalAlerts: 2 }],
|
||||
count_open_cases: 1,
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return multiple sub cases', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
const subCase2Resp = await createSubCase({ supertest, caseID: caseInfo.id, actionID });
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find`)
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql({
|
||||
...findSubCasesResp,
|
||||
total: 2,
|
||||
// find should not return the comments themselves only the stats
|
||||
subCases: [
|
||||
{
|
||||
// there should only be 1 closed sub case
|
||||
...subCase2Resp.modifiedSubCases![0],
|
||||
comments: [],
|
||||
totalComment: 1,
|
||||
totalAlerts: 2,
|
||||
status: CaseStatuses.closed,
|
||||
},
|
||||
{
|
||||
...subCase2Resp.newSubCaseInfo.subCases![0],
|
||||
comments: [],
|
||||
totalComment: 1,
|
||||
totalAlerts: 2,
|
||||
},
|
||||
],
|
||||
count_open_cases: 1,
|
||||
count_closed_cases: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('should only return open when filtering for open', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
await createSubCase({ supertest, caseID: caseInfo.id, actionID });
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?status=${CaseStatuses.open}`)
|
||||
.expect(200);
|
||||
|
||||
expect(body.total).to.be(1);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.open);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(1);
|
||||
expect(body.count_in_progress_cases).to.be(0);
|
||||
});
|
||||
|
||||
it('should only return closed when filtering for closed', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
await createSubCase({ supertest, caseID: caseInfo.id, actionID });
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?status=${CaseStatuses.closed}`)
|
||||
.expect(200);
|
||||
|
||||
expect(body.total).to.be(1);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.closed);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(1);
|
||||
expect(body.count_in_progress_cases).to.be(0);
|
||||
});
|
||||
|
||||
it('should only return in progress when filtering for in progress', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
const { newSubCaseInfo: secondSub } = await createSubCase({
|
||||
supertest,
|
||||
caseID: caseInfo.id,
|
||||
actionID,
|
||||
afterEach(async () => {
|
||||
await deleteAllCaseItems(es);
|
||||
});
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: secondSub.subCases![0].id,
|
||||
version: secondSub.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
it('should not find any sub cases when none exist', async () => {
|
||||
const { body: caseResp }: { body: CaseResponse } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCollectionReq)
|
||||
.expect(200);
|
||||
|
||||
const { body: findSubCases } = await supertest
|
||||
.get(`${getSubCasesUrl(caseResp.id)}/_find`)
|
||||
.expect(200);
|
||||
|
||||
expect(findSubCases).to.eql({
|
||||
page: 1,
|
||||
per_page: 20,
|
||||
total: 0,
|
||||
subCases: [],
|
||||
count_open_cases: 0,
|
||||
count_closed_cases: 0,
|
||||
count_in_progress_cases: 0,
|
||||
});
|
||||
});
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?status=${CaseStatuses['in-progress']}`)
|
||||
.expect(200);
|
||||
it('should return a sub cases with comment stats', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
|
||||
expect(body.total).to.be(1);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses['in-progress']);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(0);
|
||||
expect(body.count_in_progress_cases).to.be(1);
|
||||
});
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find`)
|
||||
.expect(200);
|
||||
|
||||
it('should sort on createdAt field in descending order', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
await createSubCase({
|
||||
supertest,
|
||||
caseID: caseInfo.id,
|
||||
actionID,
|
||||
expect(body).to.eql({
|
||||
...findSubCasesResp,
|
||||
total: 1,
|
||||
// find should not return the comments themselves only the stats
|
||||
subCases: [{ ...caseInfo.subCases![0], comments: [], totalComment: 1, totalAlerts: 2 }],
|
||||
count_open_cases: 1,
|
||||
});
|
||||
});
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?sortField=createdAt&sortOrder=desc`)
|
||||
.expect(200);
|
||||
it('should return multiple sub cases', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
const subCase2Resp = await createSubCase({ supertest, caseID: caseInfo.id, actionID });
|
||||
|
||||
expect(body.total).to.be(2);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.open);
|
||||
expect(body.subCases[1].status).to.be(CaseStatuses.closed);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(1);
|
||||
expect(body.count_in_progress_cases).to.be(0);
|
||||
});
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find`)
|
||||
.expect(200);
|
||||
|
||||
it('should sort on createdAt field in ascending order', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
await createSubCase({
|
||||
supertest,
|
||||
caseID: caseInfo.id,
|
||||
actionID,
|
||||
expect(body).to.eql({
|
||||
...findSubCasesResp,
|
||||
total: 2,
|
||||
// find should not return the comments themselves only the stats
|
||||
subCases: [
|
||||
{
|
||||
// there should only be 1 closed sub case
|
||||
...subCase2Resp.modifiedSubCases![0],
|
||||
comments: [],
|
||||
totalComment: 1,
|
||||
totalAlerts: 2,
|
||||
status: CaseStatuses.closed,
|
||||
},
|
||||
{
|
||||
...subCase2Resp.newSubCaseInfo.subCases![0],
|
||||
comments: [],
|
||||
totalComment: 1,
|
||||
totalAlerts: 2,
|
||||
},
|
||||
],
|
||||
count_open_cases: 1,
|
||||
count_closed_cases: 1,
|
||||
});
|
||||
});
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?sortField=createdAt&sortOrder=asc`)
|
||||
.expect(200);
|
||||
it('should only return open when filtering for open', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
await createSubCase({ supertest, caseID: caseInfo.id, actionID });
|
||||
|
||||
expect(body.total).to.be(2);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.closed);
|
||||
expect(body.subCases[1].status).to.be(CaseStatuses.open);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(1);
|
||||
expect(body.count_in_progress_cases).to.be(0);
|
||||
});
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?status=${CaseStatuses.open}`)
|
||||
.expect(200);
|
||||
|
||||
it('should sort on updatedAt field in ascending order', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
const { newSubCaseInfo: secondSub } = await createSubCase({
|
||||
supertest,
|
||||
caseID: caseInfo.id,
|
||||
actionID,
|
||||
expect(body.total).to.be(1);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.open);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(1);
|
||||
expect(body.count_in_progress_cases).to.be(0);
|
||||
});
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: secondSub.subCases![0].id,
|
||||
version: secondSub.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
it('should only return closed when filtering for closed', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
await createSubCase({ supertest, caseID: caseInfo.id, actionID });
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?status=${CaseStatuses.closed}`)
|
||||
.expect(200);
|
||||
|
||||
expect(body.total).to.be(1);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.closed);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(1);
|
||||
expect(body.count_in_progress_cases).to.be(0);
|
||||
});
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?sortField=updatedAt&sortOrder=asc`)
|
||||
.expect(200);
|
||||
it('should only return in progress when filtering for in progress', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
const { newSubCaseInfo: secondSub } = await createSubCase({
|
||||
supertest,
|
||||
caseID: caseInfo.id,
|
||||
actionID,
|
||||
});
|
||||
|
||||
expect(body.total).to.be(2);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.closed);
|
||||
expect(body.subCases[1].status).to.be(CaseStatuses['in-progress']);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(0);
|
||||
expect(body.count_in_progress_cases).to.be(1);
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: secondSub.subCases![0].id,
|
||||
version: secondSub.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?status=${CaseStatuses['in-progress']}`)
|
||||
.expect(200);
|
||||
|
||||
expect(body.total).to.be(1);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses['in-progress']);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(0);
|
||||
expect(body.count_in_progress_cases).to.be(1);
|
||||
});
|
||||
|
||||
it('should sort on createdAt field in descending order', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
await createSubCase({
|
||||
supertest,
|
||||
caseID: caseInfo.id,
|
||||
actionID,
|
||||
});
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?sortField=createdAt&sortOrder=desc`)
|
||||
.expect(200);
|
||||
|
||||
expect(body.total).to.be(2);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.open);
|
||||
expect(body.subCases[1].status).to.be(CaseStatuses.closed);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(1);
|
||||
expect(body.count_in_progress_cases).to.be(0);
|
||||
});
|
||||
|
||||
it('should sort on createdAt field in ascending order', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
await createSubCase({
|
||||
supertest,
|
||||
caseID: caseInfo.id,
|
||||
actionID,
|
||||
});
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?sortField=createdAt&sortOrder=asc`)
|
||||
.expect(200);
|
||||
|
||||
expect(body.total).to.be(2);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.closed);
|
||||
expect(body.subCases[1].status).to.be(CaseStatuses.open);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(1);
|
||||
expect(body.count_in_progress_cases).to.be(0);
|
||||
});
|
||||
|
||||
it('should sort on updatedAt field in ascending order', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// this will result in one closed case and one open
|
||||
const { newSubCaseInfo: secondSub } = await createSubCase({
|
||||
supertest,
|
||||
caseID: caseInfo.id,
|
||||
actionID,
|
||||
});
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: secondSub.subCases![0].id,
|
||||
version: secondSub.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
const { body }: { body: SubCasesFindResponse } = await supertest
|
||||
.get(`${getSubCasesUrl(caseInfo.id)}/_find?sortField=updatedAt&sortOrder=asc`)
|
||||
.expect(200);
|
||||
|
||||
expect(body.total).to.be(2);
|
||||
expect(body.subCases[0].status).to.be(CaseStatuses.closed);
|
||||
expect(body.subCases[1].status).to.be(CaseStatuses['in-progress']);
|
||||
expect(body.count_closed_cases).to.be(1);
|
||||
expect(body.count_open_cases).to.be(0);
|
||||
expect(body.count_in_progress_cases).to.be(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -37,79 +37,87 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
const supertest = getService('supertest');
|
||||
const es = getService('es');
|
||||
|
||||
describe('get_sub_case', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteAllCaseItems(es);
|
||||
// ENABLE_CASE_CONNECTOR: remove the outer describe once the case connector feature is completed
|
||||
describe('get_sub_case disabled route', () => {
|
||||
it('should return a 404 when attempting to access the route and the case connector feature is disabled', async () => {
|
||||
await supertest.get(getSubCaseDetailsUrl('case-id', 'sub-case-id')).expect(404);
|
||||
});
|
||||
|
||||
it('should return a case', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('get_sub_case', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteAllCaseItems(es);
|
||||
});
|
||||
|
||||
const { body }: { body: SubCaseResponse } = await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
it('should return a case', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
|
||||
expect(removeServerGeneratedPropertiesFromComments(body.comments)).to.eql(
|
||||
commentsResp({
|
||||
comments: [{ comment: defaultCreateSubComment, id: caseInfo.comments![0].id }],
|
||||
associationType: AssociationType.subCase,
|
||||
})
|
||||
);
|
||||
const { body }: { body: SubCaseResponse } = await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(removeServerGeneratedPropertiesFromSubCase(body)).to.eql(
|
||||
subCaseResp({ id: body.id, totalComment: 1, totalAlerts: 2 })
|
||||
);
|
||||
});
|
||||
expect(removeServerGeneratedPropertiesFromComments(body.comments)).to.eql(
|
||||
commentsResp({
|
||||
comments: [{ comment: defaultCreateSubComment, id: caseInfo.comments![0].id }],
|
||||
associationType: AssociationType.subCase,
|
||||
})
|
||||
);
|
||||
|
||||
it('should return the correct number of alerts with multiple types of alerts', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
expect(removeServerGeneratedPropertiesFromSubCase(body)).to.eql(
|
||||
subCaseResp({ id: body.id, totalComment: 1, totalAlerts: 2 })
|
||||
);
|
||||
});
|
||||
|
||||
const { body: singleAlert }: { body: CaseResponse } = await supertest
|
||||
.post(getCaseCommentsUrl(caseInfo.id))
|
||||
.query({ subCaseId: caseInfo.subCases![0].id })
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCommentAlertReq)
|
||||
.expect(200);
|
||||
it('should return the correct number of alerts with multiple types of alerts', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
|
||||
const { body }: { body: SubCaseResponse } = await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
const { body: singleAlert }: { body: CaseResponse } = await supertest
|
||||
.post(getCaseCommentsUrl(caseInfo.id))
|
||||
.query({ subCaseId: caseInfo.subCases![0].id })
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(postCommentAlertReq)
|
||||
.expect(200);
|
||||
|
||||
expect(removeServerGeneratedPropertiesFromComments(body.comments)).to.eql(
|
||||
commentsResp({
|
||||
comments: [
|
||||
{ comment: defaultCreateSubComment, id: caseInfo.comments![0].id },
|
||||
{
|
||||
comment: postCommentAlertReq,
|
||||
id: singleAlert.comments![1].id,
|
||||
},
|
||||
],
|
||||
associationType: AssociationType.subCase,
|
||||
})
|
||||
);
|
||||
const { body }: { body: SubCaseResponse } = await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(removeServerGeneratedPropertiesFromSubCase(body)).to.eql(
|
||||
subCaseResp({ id: body.id, totalComment: 2, totalAlerts: 3 })
|
||||
);
|
||||
});
|
||||
expect(removeServerGeneratedPropertiesFromComments(body.comments)).to.eql(
|
||||
commentsResp({
|
||||
comments: [
|
||||
{ comment: defaultCreateSubComment, id: caseInfo.comments![0].id },
|
||||
{
|
||||
comment: postCommentAlertReq,
|
||||
id: singleAlert.comments![1].id,
|
||||
},
|
||||
],
|
||||
associationType: AssociationType.subCase,
|
||||
})
|
||||
);
|
||||
|
||||
it('unhappy path - 404s when case is not there', async () => {
|
||||
await supertest
|
||||
.get(getSubCaseDetailsUrl('fake-case-id', 'fake-sub-case-id'))
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(404);
|
||||
expect(removeServerGeneratedPropertiesFromSubCase(body)).to.eql(
|
||||
subCaseResp({ id: body.id, totalComment: 2, totalAlerts: 3 })
|
||||
);
|
||||
});
|
||||
|
||||
it('unhappy path - 404s when case is not there', async () => {
|
||||
await supertest
|
||||
.get(getSubCaseDetailsUrl('fake-case-id', 'fake-sub-case-id'))
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -36,463 +36,475 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const es = getService('es');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('patch_sub_cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await esArchiver.load('cases/signals/default');
|
||||
});
|
||||
afterEach(async () => {
|
||||
await esArchiver.unload('cases/signals/default');
|
||||
await deleteAllCaseItems(es);
|
||||
});
|
||||
|
||||
it('should update the status of a sub case', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
const { body: subCase }: { body: SubCaseResponse } = await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.expect(200);
|
||||
|
||||
expect(subCase.status).to.eql(CaseStatuses['in-progress']);
|
||||
});
|
||||
|
||||
it('should update the status of one alert attached to a sub case', async () => {
|
||||
const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d';
|
||||
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
let signals = await getSignalsWithES({ es, indices: defaultSignalsIndex, ids: signalID });
|
||||
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be(
|
||||
CaseStatuses.open
|
||||
);
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({ es, indices: defaultSignalsIndex, ids: signalID });
|
||||
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be(
|
||||
CaseStatuses['in-progress']
|
||||
);
|
||||
});
|
||||
|
||||
it('should update the status of multiple alerts attached to a sub case', async () => {
|
||||
const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d';
|
||||
|
||||
const signalID2 = '4d0f4b1533e46b66b43bdd0330d23f39f2cf42a7253153270e38d30cce9ff0c6';
|
||||
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
{
|
||||
_id: signalID2,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
let signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be(
|
||||
CaseStatuses['in-progress']
|
||||
);
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be(
|
||||
CaseStatuses['in-progress']
|
||||
);
|
||||
});
|
||||
|
||||
it('should update the status of multiple alerts attached to multiple sub cases in one collection', async () => {
|
||||
const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d';
|
||||
const signalID2 = '4d0f4b1533e46b66b43bdd0330d23f39f2cf42a7253153270e38d30cce9ff0c6';
|
||||
|
||||
const { newSubCaseInfo: initialCaseInfo } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
caseInfo: {
|
||||
...postCollectionReq,
|
||||
settings: {
|
||||
syncAlerts: false,
|
||||
},
|
||||
},
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
// This will close the first sub case and create a new one
|
||||
const { newSubCaseInfo: collectionWithSecondSub } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
caseID: initialCaseInfo.id,
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID2,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
let signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// There should be no change in their status since syncing is disabled
|
||||
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
|
||||
);
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: collectionWithSecondSub.subCases![0].id,
|
||||
version: collectionWithSecondSub.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// There still should be no change in their status since syncing is disabled
|
||||
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
|
||||
);
|
||||
|
||||
// Turn sync alerts on
|
||||
// ENABLE_CASE_CONNECTOR: remove the outer describe once the case connector feature is completed
|
||||
describe('patch_sub_cases disabled route', () => {
|
||||
it('should return a 404 when attempting to access the route and the case connector feature is disabled', async () => {
|
||||
await supertest
|
||||
.patch(CASES_URL)
|
||||
.patch(SUB_CASES_PATCH_DEL_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
cases: [
|
||||
{
|
||||
id: collectionWithSecondSub.id,
|
||||
version: collectionWithSecondSub.version,
|
||||
settings: { syncAlerts: true },
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
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['in-progress']
|
||||
);
|
||||
.send({ subCases: [] })
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it('should update the status of alerts attached to a case and sub case when sync settings is turned on', async () => {
|
||||
const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d';
|
||||
const signalID2 = '4d0f4b1533e46b66b43bdd0330d23f39f2cf42a7253153270e38d30cce9ff0c6';
|
||||
|
||||
const { body: individualCase } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...postCaseReq,
|
||||
settings: {
|
||||
syncAlerts: false,
|
||||
},
|
||||
});
|
||||
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
caseInfo: {
|
||||
...postCollectionReq,
|
||||
settings: {
|
||||
syncAlerts: false,
|
||||
},
|
||||
},
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
describe.skip('patch_sub_cases', () => {
|
||||
let actionID: string;
|
||||
before(async () => {
|
||||
actionID = await createCaseAction(supertest);
|
||||
});
|
||||
after(async () => {
|
||||
await deleteCaseAction(supertest, actionID);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await esArchiver.load('cases/signals/default');
|
||||
});
|
||||
afterEach(async () => {
|
||||
await esArchiver.unload('cases/signals/default');
|
||||
await deleteAllCaseItems(es);
|
||||
});
|
||||
|
||||
const { body: updatedIndWithComment } = await supertest
|
||||
.post(`${CASES_URL}/${individualCase.id}/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
alertId: signalID2,
|
||||
index: defaultSignalsIndex,
|
||||
rule: { id: 'test-rule-id', name: 'test-index-id' },
|
||||
type: CommentType.alert,
|
||||
})
|
||||
.expect(200);
|
||||
it('should update the status of a sub case', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
let signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// There should be no change in their status since syncing is disabled
|
||||
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
|
||||
);
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
const updatedIndWithStatus = (
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: updatedIndWithComment.id,
|
||||
version: updatedIndWithComment.version,
|
||||
status: CaseStatuses.closed,
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'case',
|
||||
})
|
||||
)[0]; // there should only be a single entry in the response
|
||||
type: 'sub_case',
|
||||
});
|
||||
const { body: subCase }: { body: SubCaseResponse } = await supertest
|
||||
.get(getSubCaseDetailsUrl(caseInfo.id, caseInfo.subCases![0].id))
|
||||
.expect(200);
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
expect(subCase.status).to.eql(CaseStatuses['in-progress']);
|
||||
});
|
||||
|
||||
// There should still be no change in their status since syncing is disabled
|
||||
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
|
||||
);
|
||||
it('should update the status of one alert attached to a sub case', async () => {
|
||||
const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d';
|
||||
|
||||
// Turn sync alerts on
|
||||
await supertest
|
||||
.patch(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
let signals = await getSignalsWithES({ es, indices: defaultSignalsIndex, ids: signalID });
|
||||
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be(
|
||||
CaseStatuses.open
|
||||
);
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: caseInfo.id,
|
||||
version: caseInfo.version,
|
||||
settings: { syncAlerts: true },
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertest
|
||||
.patch(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
cases: [
|
||||
{
|
||||
id: updatedIndWithStatus.id,
|
||||
version: updatedIndWithStatus.version,
|
||||
settings: { syncAlerts: true },
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// alerts should be updated now that the
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be(
|
||||
CaseStatuses['in-progress']
|
||||
);
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be(
|
||||
CaseStatuses.closed
|
||||
);
|
||||
});
|
||||
|
||||
it('404s when sub case id is invalid', async () => {
|
||||
await supertest
|
||||
.patch(`${SUB_CASES_PATCH_DEL_URL}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
subCases: [
|
||||
{
|
||||
id: 'fake-id',
|
||||
version: 'blah',
|
||||
status: CaseStatuses.open,
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it('406s when updating invalid fields for a sub case', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
|
||||
await supertest
|
||||
.patch(`${SUB_CASES_PATCH_DEL_URL}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
subCases: [
|
||||
{
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
type: 'blah',
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(406);
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({ es, indices: defaultSignalsIndex, ids: signalID });
|
||||
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be(
|
||||
CaseStatuses['in-progress']
|
||||
);
|
||||
});
|
||||
|
||||
it('should update the status of multiple alerts attached to a sub case', async () => {
|
||||
const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d';
|
||||
|
||||
const signalID2 = '4d0f4b1533e46b66b43bdd0330d23f39f2cf42a7253153270e38d30cce9ff0c6';
|
||||
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
{
|
||||
_id: signalID2,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
let signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be(
|
||||
CaseStatuses['in-progress']
|
||||
);
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be(
|
||||
CaseStatuses['in-progress']
|
||||
);
|
||||
});
|
||||
|
||||
it('should update the status of multiple alerts attached to multiple sub cases in one collection', async () => {
|
||||
const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d';
|
||||
const signalID2 = '4d0f4b1533e46b66b43bdd0330d23f39f2cf42a7253153270e38d30cce9ff0c6';
|
||||
|
||||
const { newSubCaseInfo: initialCaseInfo } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
caseInfo: {
|
||||
...postCollectionReq,
|
||||
settings: {
|
||||
syncAlerts: false,
|
||||
},
|
||||
},
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
// This will close the first sub case and create a new one
|
||||
const { newSubCaseInfo: collectionWithSecondSub } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
caseID: initialCaseInfo.id,
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID2,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
let signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// There should be no change in their status since syncing is disabled
|
||||
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
|
||||
);
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: collectionWithSecondSub.subCases![0].id,
|
||||
version: collectionWithSecondSub.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// There still should be no change in their status since syncing is disabled
|
||||
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
|
||||
);
|
||||
|
||||
// Turn sync alerts on
|
||||
await supertest
|
||||
.patch(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
cases: [
|
||||
{
|
||||
id: collectionWithSecondSub.id,
|
||||
version: collectionWithSecondSub.version,
|
||||
settings: { syncAlerts: true },
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
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['in-progress']
|
||||
);
|
||||
});
|
||||
|
||||
it('should update the status of alerts attached to a case and sub case when sync settings is turned on', async () => {
|
||||
const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d';
|
||||
const signalID2 = '4d0f4b1533e46b66b43bdd0330d23f39f2cf42a7253153270e38d30cce9ff0c6';
|
||||
|
||||
const { body: individualCase } = await supertest
|
||||
.post(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...postCaseReq,
|
||||
settings: {
|
||||
syncAlerts: false,
|
||||
},
|
||||
});
|
||||
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({
|
||||
supertest,
|
||||
actionID,
|
||||
caseInfo: {
|
||||
...postCollectionReq,
|
||||
settings: {
|
||||
syncAlerts: false,
|
||||
},
|
||||
},
|
||||
comment: {
|
||||
alerts: createAlertsString([
|
||||
{
|
||||
_id: signalID,
|
||||
_index: defaultSignalsIndex,
|
||||
ruleId: 'id',
|
||||
ruleName: 'name',
|
||||
},
|
||||
]),
|
||||
type: CommentType.generatedAlert,
|
||||
},
|
||||
});
|
||||
|
||||
const { body: updatedIndWithComment } = await supertest
|
||||
.post(`${CASES_URL}/${individualCase.id}/comments`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
alertId: signalID2,
|
||||
index: defaultSignalsIndex,
|
||||
rule: { id: 'test-rule-id', name: 'test-index-id' },
|
||||
type: CommentType.alert,
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
let signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// There should be no change in their status since syncing is disabled
|
||||
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
|
||||
);
|
||||
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
status: CaseStatuses['in-progress'],
|
||||
},
|
||||
],
|
||||
type: 'sub_case',
|
||||
});
|
||||
|
||||
const updatedIndWithStatus = (
|
||||
await setStatus({
|
||||
supertest,
|
||||
cases: [
|
||||
{
|
||||
id: updatedIndWithComment.id,
|
||||
version: updatedIndWithComment.version,
|
||||
status: CaseStatuses.closed,
|
||||
},
|
||||
],
|
||||
type: 'case',
|
||||
})
|
||||
)[0]; // there should only be a single entry in the response
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// There should still be no change in their status since syncing is disabled
|
||||
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
|
||||
);
|
||||
|
||||
// Turn sync alerts on
|
||||
await supertest
|
||||
.patch(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
cases: [
|
||||
{
|
||||
id: caseInfo.id,
|
||||
version: caseInfo.version,
|
||||
settings: { syncAlerts: true },
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertest
|
||||
.patch(CASES_URL)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
cases: [
|
||||
{
|
||||
id: updatedIndWithStatus.id,
|
||||
version: updatedIndWithStatus.version,
|
||||
settings: { syncAlerts: true },
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await es.indices.refresh({ index: defaultSignalsIndex });
|
||||
|
||||
signals = await getSignalsWithES({
|
||||
es,
|
||||
indices: defaultSignalsIndex,
|
||||
ids: [signalID, signalID2],
|
||||
});
|
||||
|
||||
// alerts should be updated now that the
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be(
|
||||
CaseStatuses['in-progress']
|
||||
);
|
||||
expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be(
|
||||
CaseStatuses.closed
|
||||
);
|
||||
});
|
||||
|
||||
it('404s when sub case id is invalid', async () => {
|
||||
await supertest
|
||||
.patch(`${SUB_CASES_PATCH_DEL_URL}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
subCases: [
|
||||
{
|
||||
id: 'fake-id',
|
||||
version: 'blah',
|
||||
status: CaseStatuses.open,
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it('406s when updating invalid fields for a sub case', async () => {
|
||||
const { newSubCaseInfo: caseInfo } = await createSubCase({ supertest, actionID });
|
||||
|
||||
await supertest
|
||||
.patch(`${SUB_CASES_PATCH_DEL_URL}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
subCases: [
|
||||
{
|
||||
id: caseInfo.subCases![0].id,
|
||||
version: caseInfo.subCases![0].version,
|
||||
type: 'blah',
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(406);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -36,7 +36,20 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
describe('case_connector', () => {
|
||||
let createdActionId = '';
|
||||
|
||||
it('should return 200 when creating a case action successfully', async () => {
|
||||
it('should return 400 when creating a case action', async () => {
|
||||
await supertest
|
||||
.post('/api/actions/action')
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({
|
||||
name: 'A case connector',
|
||||
actionTypeId: '.case',
|
||||
config: {},
|
||||
})
|
||||
.expect(400);
|
||||
});
|
||||
|
||||
// ENABLE_CASE_CONNECTOR: once the case connector feature is completed unskip these tests
|
||||
it.skip('should return 200 when creating a case action successfully', async () => {
|
||||
const { body: createdAction } = await supertest
|
||||
.post('/api/actions/action')
|
||||
.set('kbn-xsrf', 'foo')
|
||||
|
@ -70,7 +83,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
describe.skip('create', () => {
|
||||
it('should respond with a 400 Bad Request when creating a case without title', async () => {
|
||||
const { body: createdAction } = await supertest
|
||||
.post('/api/actions/action')
|
||||
|
@ -500,7 +513,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
describe.skip('update', () => {
|
||||
it('should respond with a 400 Bad Request when updating a case without id', async () => {
|
||||
const { body: createdAction } = await supertest
|
||||
.post('/api/actions/action')
|
||||
|
@ -624,7 +637,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('addComment', () => {
|
||||
describe.skip('addComment', () => {
|
||||
it('should respond with a 400 Bad Request when adding a comment to a case without caseId', async () => {
|
||||
const { body: createdAction } = await supertest
|
||||
.post('/api/actions/action')
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import type { ApiResponse, estypes } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
|
||||
import * as st from 'supertest';
|
||||
|
@ -48,7 +48,7 @@ export const getSignalsWithES = async ({
|
|||
indices: string | string[];
|
||||
ids: string | string[];
|
||||
}): Promise<Map<string, Map<string, estypes.Hit<SignalHit>>>> => {
|
||||
const signals = await es.search<SignalHit>({
|
||||
const signals: ApiResponse<estypes.SearchResponse<SignalHit>> = await es.search({
|
||||
index: indices,
|
||||
body: {
|
||||
size: 10000,
|
||||
|
|
Loading…
Reference in a new issue