Skip to content

Commit

Permalink
Add bulk action outcome to the Bulk API response (elastic#125551)
Browse files Browse the repository at this point in the history
  • Loading branch information
xcrzx authored Feb 16, 2022
1 parent 04e87d5 commit e1b9f93
Show file tree
Hide file tree
Showing 28 changed files with 448 additions and 382 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
BulkRuleResponse,
PatchRuleProps,
BulkActionProps,
BulkActionResponse,
BulkActionResponseMap,
PreviewRulesProps,
} from './types';
import { KibanaServices } from '../../../../common/lib/kibana';
Expand Down Expand Up @@ -266,16 +266,19 @@ export const performBulkAction = async <Action extends BulkAction>({
query,
edit,
ids,
}: BulkActionProps<Action>): Promise<BulkActionResponse<Action>> =>
KibanaServices.get().http.fetch<BulkActionResponse<Action>>(DETECTION_ENGINE_RULES_BULK_ACTION, {
method: 'POST',
body: JSON.stringify({
action,
...(edit ? { edit } : {}),
...(ids ? { ids } : {}),
...(query !== undefined ? { query } : {}),
}),
});
}: BulkActionProps<Action>): Promise<BulkActionResponseMap<Action>> =>
KibanaServices.get().http.fetch<BulkActionResponseMap<Action>>(
DETECTION_ENGINE_RULES_BULK_ACTION,
{
method: 'POST',
body: JSON.stringify({
action,
...(edit ? { edit } : {}),
...(ids ? { ids } : {}),
...(query !== undefined ? { query } : {}),
}),
}
);

/**
* Create Prepackaged Rules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,41 @@ export interface BulkActionProps<Action extends BulkAction> {
edit?: BulkActionEditPayload[];
}

export interface BulkActionSummary {
failed: number;
succeeded: number;
total: number;
}

export interface BulkActionResult {
success: boolean;
rules_count: number;
updated: Rule[];
created: Rule[];
deleted: Rule[];
}

export interface BulkActionAggregatedError {
message: string;
status_code: number;
rules: Array<{ id: string; name?: string }>;
}

export interface BulkActionResponse {
success?: boolean;
rules_count?: number;
attributes: {
summary: BulkActionSummary;
results: BulkActionResult;
errors?: BulkActionAggregatedError[];
};
}

export type BulkActionResponse<Action extends BulkAction> = {
[BulkAction.delete]: BulkActionResult;
[BulkAction.disable]: BulkActionResult;
[BulkAction.enable]: BulkActionResult;
[BulkAction.duplicate]: BulkActionResult;
export type BulkActionResponseMap<Action extends BulkAction> = {
[BulkAction.delete]: BulkActionResponse;
[BulkAction.disable]: BulkActionResponse;
[BulkAction.enable]: BulkActionResponse;
[BulkAction.duplicate]: BulkActionResponse;
[BulkAction.export]: Blob;
[BulkAction.edit]: BulkActionResult;
[BulkAction.edit]: BulkActionResponse;
}[Action];

export interface BasicFetchProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ const executeRulesBulkAction = async ({
} else {
const response = await performBulkAction({ ...search, action, edit: payload?.edit });

onSuccess?.({ rulesCount: response.rules_count });
onSuccess?.({ rulesCount: response.attributes.summary.succeeded });
}
} catch (e) {
if (onError) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts';
import { useIsExperimentalFeatureEnabled } from '../../../../../../common/hooks/use_experimental_features';
import { convertRulesFilterToKQL } from '../../../../../containers/detection_engine/rules/utils';

import type { FilterOptions } from '../../../../../containers/detection_engine/rules/types';
import type { BulkActionPartialErrorResponse } from '../../../../../../../common/detection_engine/schemas/response/perform_bulk_action_schema';
import type {
BulkActionResponse,
FilterOptions,
} from '../../../../../containers/detection_engine/rules/types';
import type { HTTPError } from '../../../../../../../common/detection_engine/types';
import { useInvalidateRules } from '../../../../../containers/detection_engine/rules/use_find_rules_query';

Expand Down Expand Up @@ -300,8 +302,8 @@ export const useBulkActions = ({
hideWarningToast();
// if response doesn't have number of failed rules, it means the whole bulk action failed
// and general error toast will be shown. Otherwise - error toast for partial failure
const failedRulesCount = (error?.body as BulkActionPartialErrorResponse)?.attributes
?.rules?.failed;
const failedRulesCount = (error?.body as BulkActionResponse)?.attributes?.summary
?.failed;

if (isNaN(failedRulesCount)) {
toasts.addError(error, { title: i18n.BULK_ACTION_FAILED });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ const buildResponses = (method: Method, calls: MockCall[]): ResponseCall[] => {
status: call.statusCode,
body: JSON.parse(call.body),
}));
case 'customError':
return calls.map(([call]) => ({
status: call.statusCode,
body: call.body,
}));
default:
throw new Error(`Encountered unexpected call to response.${method}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '../../../../../common/constants';
import { SetupPlugins } from '../../../../plugin';
import { buildMlAuthz } from '../../../machine_learning/authz';
import { throwHttpError } from '../../../machine_learning/validation';
import { throwAuthzError } from '../../../machine_learning/validation';
import { readRules } from '../../rules/read_rules';
import { getDuplicates } from './utils';
import { transformValidateBulkError } from './validate';
Expand Down Expand Up @@ -92,7 +92,7 @@ export const createRulesBulkRoute = (
});
}

throwHttpError(await mlAuthz.validateRuleType(internalRule.params.type));
throwAuthzError(await mlAuthz.validateRuleType(internalRule.params.type));
const finalIndex = internalRule.params.outputIndex;
const indexExists = await getIndexExists(esClient.asCurrentUser, finalIndex);
if (!isRuleRegistryEnabled && !indexExists) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import { SetupPlugins } from '../../../../plugin';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { buildMlAuthz } from '../../../machine_learning/authz';
import { throwHttpError } from '../../../machine_learning/validation';
import { throwAuthzError } from '../../../machine_learning/validation';
import { readRules } from '../../rules/read_rules';
import { buildSiemResponse } from '../utils';

Expand Down Expand Up @@ -79,7 +79,7 @@ export const createRulesRoute = (
request,
savedObjectsClient,
});
throwHttpError(await mlAuthz.validateRuleType(internalRule.params.type));
throwAuthzError(await mlAuthz.validateRuleType(internalRule.params.type));

const indexExists = await getIndexExists(
esClient.asCurrentUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { SecuritySolutionPluginRouter } from '../../../../types';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { SetupPlugins } from '../../../../plugin';
import { buildMlAuthz } from '../../../machine_learning/authz';
import { throwHttpError } from '../../../machine_learning/validation';
import { throwAuthzError } from '../../../machine_learning/validation';
import { transformBulkError, buildSiemResponse } from '../utils';
import { getIdBulkError } from './utils';
import { transformValidateBulkError } from './validate';
Expand Down Expand Up @@ -117,7 +117,7 @@ export const patchRulesBulkRoute = (
try {
if (type) {
// reject an unauthorized "promotion" to ML
throwHttpError(await mlAuthz.validateRuleType(type));
throwAuthzError(await mlAuthz.validateRuleType(type));
}

const existingRule = await readRules({
Expand All @@ -128,7 +128,7 @@ export const patchRulesBulkRoute = (
});
if (existingRule?.params.type) {
// reject an unauthorized modification of an ML rule
throwHttpError(await mlAuthz.validateRuleType(existingRule?.params.type));
throwAuthzError(await mlAuthz.validateRuleType(existingRule?.params.type));
}

const migratedRule = await legacyMigrate({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { SecuritySolutionPluginRouter } from '../../../../types';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { SetupPlugins } from '../../../../plugin';
import { buildMlAuthz } from '../../../machine_learning/authz';
import { throwHttpError } from '../../../machine_learning/validation';
import { throwAuthzError } from '../../../machine_learning/validation';
import { patchRules } from '../../rules/patch_rules';
import { buildSiemResponse } from '../utils';

Expand Down Expand Up @@ -118,7 +118,7 @@ export const patchRulesRoute = (
});
if (type) {
// reject an unauthorized "promotion" to ML
throwHttpError(await mlAuthz.validateRuleType(type));
throwAuthzError(await mlAuthz.validateRuleType(type));
}

const existingRule = await readRules({
Expand All @@ -129,7 +129,7 @@ export const patchRulesRoute = (
});
if (existingRule?.params.type) {
// reject an unauthorized modification of an ML rule
throwHttpError(await mlAuthz.validateRuleType(existingRule?.params.type));
throwAuthzError(await mlAuthz.validateRuleType(existingRule?.params.type));
}

const migratedRule = await legacyMigrate({
Expand Down
Loading

0 comments on commit e1b9f93

Please sign in to comment.