Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cases] Route: Get all alerts attach to a case #101878

Merged
merged 12 commits into from
Jun 18, 2021
18 changes: 18 additions & 0 deletions x-pack/plugins/cases/common/api/cases/alerts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import * as rt from 'io-ts';

const AlertRt = rt.type({
id: rt.string,
index: rt.string,
attached_at: rt.string,
});

export const AlertResponseRt = rt.array(AlertRt);

export type AlertResponse = rt.TypeOf<typeof AlertResponseRt>;
1 change: 1 addition & 0 deletions x-pack/plugins/cases/common/api/cases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from './status';
export * from './user_actions';
export * from './sub_case';
export * from './constants';
export * from './alerts';
1 change: 1 addition & 0 deletions x-pack/plugins/cases/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const CASE_TAGS_URL = `${CASES_URL}/tags`;
export const CASE_USER_ACTIONS_URL = `${CASE_DETAILS_URL}/user_actions`;

export const CASE_ALERTS_URL = `${CASES_URL}/alerts/{alert_id}`;
export const CASE_DETAILS_ALERTS_URL = `${CASE_DETAILS_URL}/alerts`;

/**
* Action routes
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions x-pack/plugins/cases/server/authorization/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,14 @@ export const Operations: Record<ReadOperations | WriteOperations, OperationDetai
docType: 'case',
savedObjectType: CASE_SAVED_OBJECT,
},
[ReadOperations.GetAlertsAttachedToCase]: {
jonathan-buttner marked this conversation as resolved.
Show resolved Hide resolved
ecsType: EVENT_TYPES.access,
name: ACCESS_COMMENT_OPERATION,
action: 'case_comment_alerts_attach_to_case',
verbs: accessVerbs,
docType: 'comments',
savedObjectType: CASE_COMMENT_SAVED_OBJECT,
},
// comments operations
[WriteOperations.CreateComment]: {
ecsType: EVENT_TYPES.creation,
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/cases/server/authorization/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export enum ReadOperations {
GetReporters = 'getReporters',
FindConfigurations = 'findConfigurations',
GetUserActions = 'getUserActions',
GetAlertsAttachedToCase = 'getAlertsAttachedToCase',
}

/**
Expand Down
21 changes: 1 addition & 20 deletions x-pack/plugins/cases/server/client/alerts/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,11 @@
* 2.0.
*/

import { CaseStatuses } from '../../../common/api';
import { AlertInfo } from '../../common';
import { CasesClientGetAlertsResponse } from './types';
import { AlertGet, AlertUpdateStatus, CasesClientGetAlertsResponse } from './types';
import { get } from './get';
import { updateStatus } from './update_status';
import { CasesClientArgs } from '../types';

/**
cnasikas marked this conversation as resolved.
Show resolved Hide resolved
* Defines the fields necessary to update an alert's status.
*/
export interface UpdateAlertRequest {
id: string;
index: string;
status: CaseStatuses;
}

export interface AlertUpdateStatus {
alerts: UpdateAlertRequest[];
}

export interface AlertGet {
alertsInfo: AlertInfo[];
}

export interface AlertSubClient {
get(args: AlertGet): Promise<CasesClientGetAlertsResponse>;
updateStatus(args: AlertUpdateStatus): Promise<void>;
Expand Down
9 changes: 2 additions & 7 deletions x-pack/plugins/cases/server/client/alerts/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@
* 2.0.
*/

import { AlertInfo } from '../../common';
import { CasesClientGetAlertsResponse } from './types';
import { CasesClientGetAlertsResponse, AlertGet } from './types';
import { CasesClientArgs } from '..';

interface GetParams {
alertsInfo: AlertInfo[];
}

export const get = async (
{ alertsInfo }: GetParams,
{ alertsInfo }: AlertGet,
clientArgs: CasesClientArgs
): Promise<CasesClientGetAlertsResponse> => {
const { alertsService, scopedClusterClient, logger } = clientArgs;
Expand Down
20 changes: 20 additions & 0 deletions x-pack/plugins/cases/server/client/alerts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* 2.0.
*/

import { CaseStatuses } from '../../../common/api';
import { AlertInfo } from '../../common';

interface Alert {
id: string;
index: string;
Expand All @@ -17,3 +20,20 @@ interface Alert {
}

export type CasesClientGetAlertsResponse = Alert[];

/**
* Defines the fields necessary to update an alert's status.
*/
export interface UpdateAlertRequest {
id: string;
index: string;
status: CaseStatuses;
}

export interface AlertUpdateStatus {
alerts: UpdateAlertRequest[];
}

export interface AlertGet {
alertsInfo: AlertInfo[];
}
2 changes: 1 addition & 1 deletion x-pack/plugins/cases/server/client/alerts/update_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* 2.0.
*/

import { UpdateAlertRequest } from './client';
import { CasesClientArgs } from '..';
import { UpdateAlertRequest } from './types';

interface UpdateAlertsStatusArgs {
alerts: UpdateAlertRequest[];
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/cases/server/client/cases/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
User,
AllTagsFindRequest,
AllReportersFindRequest,
AlertResponse,
} from '../../../common/api';
import { CasesClient } from '../client';
import { CasesClientInternal } from '../client_internal';
Expand All @@ -30,6 +31,8 @@ import { find } from './find';
import {
CaseIDsByAlertIDParams,
get,
getAllAlertsAttachToCase,
GetAllAlertsAttachToCase,
getCaseIDsByAlertID,
GetParams,
getReporters,
Expand Down Expand Up @@ -82,6 +85,10 @@ export interface CasesSubClient {
* Retrieves the case IDs given a single alert ID
*/
getCaseIDsByAlertID(params: CaseIDsByAlertIDParams): Promise<string[]>;
/**
* Retrieves all alerts attach to a case given a single case ID
*/
getAllAlertsAttachToCase(params: GetAllAlertsAttachToCase): Promise<AlertResponse>;
jonathan-buttner marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand All @@ -105,6 +112,8 @@ export const createCasesSubClient = (
getReporters: (params: AllReportersFindRequest) => getReporters(params, clientArgs),
getCaseIDsByAlertID: (params: CaseIDsByAlertIDParams) =>
getCaseIDsByAlertID(params, clientArgs),
getAllAlertsAttachToCase: (params: GetAllAlertsAttachToCase) =>
getAllAlertsAttachToCase(params, clientArgs, casesClient),
};

return Object.freeze(casesSubClient);
Expand Down
66 changes: 64 additions & 2 deletions x-pack/plugins/cases/server/client/cases/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,77 @@ import {
AllReportersFindRequest,
CasesByAlertIDRequest,
CasesByAlertIDRequestRt,
AlertResponse,
AttributesTypeAlerts,
} from '../../../common/api';
import { countAlertsForID, flattenCaseSavedObject } from '../../common';
import { countAlertsForID, flattenCaseSavedObject, getIDsAndIndicesAsArrays } from '../../common';
import { createCaseError } from '../../common/error';
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
import { CasesClientArgs } from '..';
import { CasesClient, CasesClientArgs } from '..';
import { Operations } from '../../authorization';
import { combineAuthorizedAndOwnerFilter } from '../utils';
import { CasesService } from '../../services';

const normalizeAlertResponse = (alerts: Array<SavedObject<AttributesTypeAlerts>>): AlertResponse =>
alerts.reduce((acc: AlertResponse, alert) => {
const { ids, indices } = getIDsAndIndicesAsArrays(alert.attributes);

if (ids.length !== indices.length) {
return acc;
}

return [
...acc,
...ids.map((id, index) => ({
id,
index: indices[index],
attached_at: alert.attributes.created_at,
})),
];
}, []);

export interface GetAllAlertsAttachToCase {
caseId: string;
}

export const getAllAlertsAttachToCase = async (
{ caseId }: GetAllAlertsAttachToCase,
clientArgs: CasesClientArgs,
casesClient: CasesClient
): Promise<AlertResponse> => {
const { unsecuredSavedObjectsClient, authorization, caseService } = clientArgs;
const theCase = await casesClient.cases.get({
jonathan-buttner marked this conversation as resolved.
Show resolved Hide resolved
id: caseId,
includeComments: false,
includeSubCaseComments: false,
});

await authorization.ensureAuthorized({
jonathan-buttner marked this conversation as resolved.
Show resolved Hide resolved
entities: [{ owner: theCase.owner, id: caseId }],
operation: Operations.getAlertsAttachedToCase,
});

const {
filter: authorizationFilter,
ensureSavedObjectsAreAuthorized,
} = await authorization.getAuthorizationFilter(Operations.getAlertsAttachedToCase);

const alerts = await caseService.getAllAlertsAttachToCase({
unsecuredSavedObjectsClient,
caseId: theCase.id,
filter: authorizationFilter,
});

ensureSavedObjectsAreAuthorized(
alerts.map((alert) => ({
owner: alert.attributes.owner,
id: alert.id,
}))
);

return normalizeAlertResponse(alerts);
};

/**
* Parameters for finding cases IDs using an alert ID
*/
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/cases/server/client/cases/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
} from '../../common';
import { createCaseError } from '../../common/error';
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
import { UpdateAlertRequest } from '../alerts/client';
import { UpdateAlertRequest } from '../alerts/types';
import { CasesClientInternal } from '../client_internal';
import { CasesClientArgs } from '..';
import { Operations, OwnerEntity } from '../../authorization';
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/cases/server/client/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const createCasesSubClientMock = (): CasesSubClientMock => {
getTags: jest.fn(),
getReporters: jest.fn(),
getCaseIDsByAlertID: jest.fn(),
getAllAlertsAttachToCase: jest.fn(),
};
};

Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/cases/server/client/sub_cases/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
flattenSubCaseSavedObject,
} from '../../common';
import { createCaseError } from '../../common/error';
import { UpdateAlertRequest } from '../../client/alerts/client';
import { UpdateAlertRequest } from '../../client/alerts/types';
import { CasesClientArgs } from '../types';
import { CasesClientInternal } from '../client_internal';

Expand Down
Loading