mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Add UUID to RuleAction (#148038)
Resolves: [#149587](https://github.com/elastic/kibana/issues/149587) This PR intends to add a `uuid` field to the rule actions. A migration script add a uuid to all the existing actions. Create method of the rule_client (and create endpoint) accepts a rule.actions data without uuid and adds a new uuid to the all actions. Update and bulkEdit methods of the rule_client (and update and bulk_edit endpoints) accepts rule.actions data with and without uuid. As a user can add a new action to an existing rule, UI should send the uuid of an existing action back then update and bulkEdit methods would add the uuid's to all the new actions. All the get methods return uuid in the actions. Since we don't query by the uuid of an action, I marked actions as `dynamic: false` in the mappings so we don't need to add the uuid to the mappings. I tried not to modify the legacy APIs, therefore i used some type castings there, but please let me know if they need to be modified as well. ## To verify: Create a rule with some actions and save. Then add some more actions and expect all of them to have an auto-generated uuid field and still work as they were. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
8440a299a6
commit
f562b3c289
65 changed files with 785 additions and 151 deletions
|
@ -5,6 +5,7 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import { NonEmptyString } from '@kbn/securitysolution-io-ts-types';
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { saved_object_attributes } from '../saved_object_attributes';
|
||||
|
@ -18,6 +19,9 @@ export const RuleActionId = t.string;
|
|||
export type RuleActionTypeId = t.TypeOf<typeof RuleActionTypeId>;
|
||||
export const RuleActionTypeId = t.string;
|
||||
|
||||
export type RuleActionUuid = t.TypeOf<typeof RuleActionUuid>;
|
||||
export const RuleActionUuid = NonEmptyString;
|
||||
|
||||
/**
|
||||
* Params is an "object", since it is a type of RuleActionParams which is action templates.
|
||||
* @see x-pack/plugins/alerting/common/rule.ts
|
||||
|
@ -27,12 +31,15 @@ export const RuleActionParams = saved_object_attributes;
|
|||
|
||||
export type RuleAction = t.TypeOf<typeof RuleAction>;
|
||||
export const RuleAction = t.exact(
|
||||
t.type({
|
||||
group: RuleActionGroup,
|
||||
id: RuleActionId,
|
||||
action_type_id: RuleActionTypeId,
|
||||
params: RuleActionParams,
|
||||
})
|
||||
t.intersection([
|
||||
t.type({
|
||||
group: RuleActionGroup,
|
||||
id: RuleActionId,
|
||||
action_type_id: RuleActionTypeId,
|
||||
params: RuleActionParams,
|
||||
}),
|
||||
t.partial({ uuid: RuleActionUuid }),
|
||||
])
|
||||
);
|
||||
|
||||
export type RuleActionArray = t.TypeOf<typeof RuleActionArray>;
|
||||
|
@ -40,12 +47,15 @@ export const RuleActionArray = t.array(RuleAction);
|
|||
|
||||
export type RuleActionCamel = t.TypeOf<typeof RuleActionCamel>;
|
||||
export const RuleActionCamel = t.exact(
|
||||
t.type({
|
||||
group: RuleActionGroup,
|
||||
id: RuleActionId,
|
||||
actionTypeId: RuleActionTypeId,
|
||||
params: RuleActionParams,
|
||||
})
|
||||
t.intersection([
|
||||
t.type({
|
||||
group: RuleActionGroup,
|
||||
id: RuleActionId,
|
||||
actionTypeId: RuleActionTypeId,
|
||||
params: RuleActionParams,
|
||||
}),
|
||||
t.partial({ uuid: RuleActionUuid }),
|
||||
])
|
||||
);
|
||||
|
||||
export type RuleActionArrayCamel = t.TypeOf<typeof RuleActionArrayCamel>;
|
||||
|
|
|
@ -57,7 +57,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
|
|||
Object {
|
||||
"action": "6cfc277ed3211639e37546ac625f4a68f2494215",
|
||||
"action_task_params": "db2afea7d78e00e725486b791554d0d4e81956ef",
|
||||
"alert": "f81ad957a7936522482e4539c7a96a963ebdbc3e",
|
||||
"alert": "2568bf6d8ba0876441c61c9e58e08016c1dc1617",
|
||||
"api_key_pending_invalidation": "16e7bcf8e78764102d7f525542d5b616809a21ee",
|
||||
"apm-indices": "d19dd7fb51f2d2cbc1f8769481721e0953f9a6d2",
|
||||
"apm-server-schema": "1d42f17eff9ec6c16d3a9324d9539e2d123d0a9a",
|
||||
|
|
|
@ -77,6 +77,7 @@ export type RuleActionParams = SavedObjectAttributes;
|
|||
export type RuleActionParam = SavedObjectAttribute;
|
||||
|
||||
export interface RuleAction {
|
||||
uuid?: string;
|
||||
group: string;
|
||||
id: string;
|
||||
actionTypeId: string;
|
||||
|
|
|
@ -109,6 +109,7 @@ describe('loadRule', () => {
|
|||
"params": Object {
|
||||
"message": "alert 37: {{context.message}}",
|
||||
},
|
||||
"uuid": "123-456",
|
||||
},
|
||||
],
|
||||
"alertTypeId": ".index-threshold",
|
||||
|
@ -278,6 +279,7 @@ function getApiRule() {
|
|||
},
|
||||
group: 'threshold met',
|
||||
id: '3619a0d0-582b-11ec-8995-2b1578a3bc5d',
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
params: { x: 42 },
|
||||
|
@ -319,6 +321,7 @@ function getRule(): Rule<{ x: number }> {
|
|||
},
|
||||
group: 'threshold met',
|
||||
id: '3619a0d0-582b-11ec-8995-2b1578a3bc5d',
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
params: { x: 42 },
|
||||
|
|
|
@ -31,6 +31,7 @@ describe('common_transformations', () => {
|
|||
group: 'some group',
|
||||
id: 'some-connector-id',
|
||||
params: { foo: 'car', bar: [1, 2, 3] },
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
params: { bar: 'foo', numbers: { 1: [2, 3] } } as never,
|
||||
|
@ -108,6 +109,7 @@ describe('common_transformations', () => {
|
|||
],
|
||||
"foo": "car",
|
||||
},
|
||||
"uuid": "123-456",
|
||||
},
|
||||
],
|
||||
"alertTypeId": "some-rule-type",
|
||||
|
@ -213,6 +215,7 @@ describe('common_transformations', () => {
|
|||
group: 'some group',
|
||||
id: 'some-connector-id',
|
||||
params: {},
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
params: {} as never,
|
||||
|
@ -277,6 +280,7 @@ describe('common_transformations', () => {
|
|||
"group": "some group",
|
||||
"id": "some-connector-id",
|
||||
"params": Object {},
|
||||
"uuid": "123-456",
|
||||
},
|
||||
],
|
||||
"alertTypeId": "some-rule-type",
|
||||
|
|
|
@ -41,6 +41,7 @@ describe('bulkEditInternalRulesRoute', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
consumer: 'bar',
|
||||
|
@ -111,6 +112,7 @@ describe('bulkEditInternalRulesRoute', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,7 @@ const ruleActionSchema = schema.object({
|
|||
group: schema.string(),
|
||||
id: schema.string(),
|
||||
params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }),
|
||||
uuid: schema.maybe(schema.string()),
|
||||
});
|
||||
|
||||
const operationsSchema = schema.arrayOf(
|
||||
|
|
|
@ -48,6 +48,7 @@ describe('cloneRuleRoute', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
enabled: true,
|
||||
|
@ -97,6 +98,7 @@ describe('cloneRuleRoute', () => {
|
|||
{
|
||||
...ruleToClone.actions[0],
|
||||
connector_type_id: 'test',
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -51,6 +51,7 @@ describe('createRuleRoute', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
enabled: true,
|
||||
|
@ -100,6 +101,7 @@ describe('createRuleRoute', () => {
|
|||
{
|
||||
...ruleToCreate.actions[0],
|
||||
connector_type_id: 'test',
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -44,6 +44,7 @@ describe('getRuleRoute', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
consumer: 'bar',
|
||||
|
@ -85,6 +86,7 @@ describe('getRuleRoute', () => {
|
|||
id: mockedAlert.actions[0].id,
|
||||
params: mockedAlert.actions[0].params,
|
||||
connector_type_id: mockedAlert.actions[0].actionTypeId,
|
||||
uuid: mockedAlert.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -60,7 +60,7 @@ const rewriteBodyRes: RewriteResponseCase<SanitizedRule<RuleTypeParams>> = ({
|
|||
last_execution_date: executionStatus.lastExecutionDate,
|
||||
last_duration: executionStatus.lastDuration,
|
||||
},
|
||||
actions: actions.map(({ group, id, actionTypeId, params, frequency }) => ({
|
||||
actions: actions.map(({ group, id, actionTypeId, params, frequency, uuid }) => ({
|
||||
group,
|
||||
id,
|
||||
params,
|
||||
|
@ -72,6 +72,7 @@ const rewriteBodyRes: RewriteResponseCase<SanitizedRule<RuleTypeParams>> = ({
|
|||
throttle: frequency.throttle,
|
||||
}
|
||||
: undefined,
|
||||
...(uuid && { uuid }),
|
||||
})),
|
||||
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),
|
||||
...(nextRun ? { next_run: nextRun } : {}),
|
||||
|
|
|
@ -24,6 +24,7 @@ export const actionsSchema = schema.arrayOf(
|
|||
throttle: schema.nullable(schema.string({ validate: validateDurationSchema })),
|
||||
})
|
||||
),
|
||||
uuid: schema.maybe(schema.string()),
|
||||
}),
|
||||
{ defaultValue: [] }
|
||||
);
|
||||
|
|
|
@ -57,7 +57,7 @@ export const rewriteRule = ({
|
|||
last_execution_date: executionStatus.lastExecutionDate,
|
||||
last_duration: executionStatus.lastDuration,
|
||||
},
|
||||
actions: actions.map(({ group, id, actionTypeId, params, frequency }) => ({
|
||||
actions: actions.map(({ group, id, actionTypeId, params, frequency, uuid }) => ({
|
||||
group,
|
||||
id,
|
||||
params,
|
||||
|
@ -71,6 +71,7 @@ export const rewriteRule = ({
|
|||
},
|
||||
}
|
||||
: {}),
|
||||
...(uuid && { uuid }),
|
||||
})),
|
||||
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),
|
||||
...(nextRun ? { next_run: nextRun } : {}),
|
||||
|
|
|
@ -44,6 +44,7 @@ describe('resolveRuleRoute', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
consumer: 'bar',
|
||||
|
@ -97,6 +98,7 @@ describe('resolveRuleRoute', () => {
|
|||
id: mockedRule.actions[0].id,
|
||||
params: mockedRule.actions[0].params,
|
||||
connector_type_id: mockedRule.actions[0].actionTypeId,
|
||||
uuid: mockedRule.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
outcome: 'aliasMatch',
|
||||
|
|
|
@ -42,6 +42,7 @@ describe('updateRuleRoute', () => {
|
|||
updatedAt: new Date(),
|
||||
actions: [
|
||||
{
|
||||
uuid: '1234-5678',
|
||||
group: 'default',
|
||||
id: '2',
|
||||
actionTypeId: 'test',
|
||||
|
@ -58,6 +59,7 @@ describe('updateRuleRoute', () => {
|
|||
notify_when: mockedAlert.notifyWhen,
|
||||
actions: [
|
||||
{
|
||||
uuid: '1234-5678',
|
||||
group: mockedAlert.actions[0].group,
|
||||
id: mockedAlert.actions[0].id,
|
||||
params: mockedAlert.actions[0].params,
|
||||
|
@ -114,6 +116,7 @@ describe('updateRuleRoute', () => {
|
|||
"params": Object {
|
||||
"baz": true,
|
||||
},
|
||||
"uuid": "1234-5678",
|
||||
},
|
||||
],
|
||||
"name": "abc",
|
||||
|
|
16
x-pack/plugins/alerting/server/rules_client/lib/add_uuid.ts
Normal file
16
x-pack/plugins/alerting/server/rules_client/lib/add_uuid.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* 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 { v4 } from 'uuid';
|
||||
import { NormalizedAlertAction, NormalizedAlertActionWithUuid } from '..';
|
||||
|
||||
export function addUuid(actions: NormalizedAlertAction[] = []): NormalizedAlertActionWithUuid[] {
|
||||
return actions.map((action) => ({
|
||||
...action,
|
||||
uuid: action.uuid || v4(),
|
||||
}));
|
||||
}
|
|
@ -8,12 +8,11 @@
|
|||
import { SavedObjectReference } from '@kbn/core/server';
|
||||
import { RawRule } from '../../types';
|
||||
import { preconfiguredConnectorActionRefPrefix } from '../common/constants';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { NormalizedAlertAction } from '../types';
|
||||
import { NormalizedAlertActionWithUuid, RulesClientContext } from '../types';
|
||||
|
||||
export async function denormalizeActions(
|
||||
context: RulesClientContext,
|
||||
alertActions: NormalizedAlertAction[]
|
||||
alertActions: NormalizedAlertActionWithUuid[]
|
||||
): Promise<{ actions: RawRule['actions']; references: SavedObjectReference[] }> {
|
||||
const references: SavedObjectReference[] = [];
|
||||
const actions: RawRule['actions'] = [];
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { SavedObjectReference } from '@kbn/core/server';
|
||||
import { RawRule, RuleTypeParams } from '../../types';
|
||||
import { UntypedNormalizedRuleType } from '../../rule_type_registry';
|
||||
import { NormalizedAlertAction } from '../types';
|
||||
import { NormalizedAlertActionWithUuid } from '../types';
|
||||
import { extractedSavedObjectParamReferenceNamePrefix } from '../common/constants';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { denormalizeActions } from './denormalize_actions';
|
||||
|
@ -19,7 +19,7 @@ export async function extractReferences<
|
|||
>(
|
||||
context: RulesClientContext,
|
||||
ruleType: UntypedNormalizedRuleType,
|
||||
ruleActions: NormalizedAlertAction[],
|
||||
ruleActions: NormalizedAlertActionWithUuid[],
|
||||
ruleParams: Params
|
||||
): Promise<{
|
||||
actions: RawRule['actions'];
|
||||
|
|
|
@ -15,3 +15,4 @@ export { checkAuthorizationAndGetTotal } from './check_authorization_and_get_tot
|
|||
export { scheduleTask } from './schedule_task';
|
||||
export { createNewAPIKeySet } from './create_new_api_key_set';
|
||||
export { recoverRuleAlerts } from './recover_rule_alerts';
|
||||
export { addUuid } from './add_uuid';
|
||||
|
|
|
@ -31,6 +31,15 @@ export async function validateActions(
|
|||
|
||||
const errors = [];
|
||||
|
||||
const uniqueActions = new Set(actions.map((action) => action.uuid));
|
||||
if (uniqueActions.size < actions.length) {
|
||||
errors.push(
|
||||
i18n.translate('xpack.alerting.rulesClient.validateActions.hasDuplicatedUuid', {
|
||||
defaultMessage: 'Actions have duplicated UUIDs',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// check for actions using connectors with missing secrets
|
||||
const actionsClient = await context.getActionsClient();
|
||||
const actionIds = [...new Set(actions.map((action) => action.id))];
|
||||
|
|
|
@ -54,13 +54,14 @@ import {
|
|||
API_KEY_GENERATE_CONCURRENCY,
|
||||
} from '../common/constants';
|
||||
import { getMappedParams } from '../common/mapped_params_utils';
|
||||
import { getAlertFromRaw, extractReferences, validateActions, updateMeta } from '../lib';
|
||||
import { getAlertFromRaw, extractReferences, validateActions, updateMeta, addUuid } from '../lib';
|
||||
import {
|
||||
NormalizedAlertAction,
|
||||
BulkOperationError,
|
||||
RuleBulkOperationAggregation,
|
||||
RulesClientContext,
|
||||
CreateAPIKeyResult,
|
||||
NormalizedAlertActionWithUuid,
|
||||
} from '../types';
|
||||
|
||||
export type BulkEditFields = keyof Pick<
|
||||
|
@ -452,7 +453,7 @@ async function updateRuleAttributesAndParamsInMemory<Params extends RuleTypePara
|
|||
} = await extractReferences(
|
||||
context,
|
||||
ruleType,
|
||||
ruleActions.actions,
|
||||
ruleActions.actions as NormalizedAlertActionWithUuid[],
|
||||
validatedMutatedAlertTypeParams
|
||||
);
|
||||
|
||||
|
@ -527,7 +528,11 @@ async function getUpdatedAttributesFromOperations(
|
|||
) {
|
||||
let attributes = cloneDeep(rule.attributes);
|
||||
let ruleActions = {
|
||||
actions: injectReferencesIntoActions(rule.id, rule.attributes.actions, rule.references || []),
|
||||
actions: injectReferencesIntoActions(
|
||||
rule.id,
|
||||
rule.attributes.actions || [],
|
||||
rule.references || []
|
||||
),
|
||||
};
|
||||
|
||||
let hasUpdateApiKeyOperation = false;
|
||||
|
@ -540,23 +545,28 @@ async function getUpdatedAttributesFromOperations(
|
|||
// the `isAttributesUpdateSkipped` flag to false.
|
||||
switch (operation.field) {
|
||||
case 'actions': {
|
||||
const updatedOperation = {
|
||||
...operation,
|
||||
value: addUuid(operation.value),
|
||||
};
|
||||
|
||||
try {
|
||||
await validateActions(context, ruleType, {
|
||||
...attributes,
|
||||
actions: operation.value,
|
||||
actions: updatedOperation.value,
|
||||
});
|
||||
} catch (e) {
|
||||
// If validateActions fails on the first attempt, it may be because of legacy rule-level frequency params
|
||||
attributes = await attemptToMigrateLegacyFrequency(
|
||||
context,
|
||||
operation,
|
||||
updatedOperation,
|
||||
attributes,
|
||||
ruleType
|
||||
);
|
||||
}
|
||||
|
||||
const { modifiedAttributes, isAttributeModified } = applyBulkEditOperation(
|
||||
operation,
|
||||
updatedOperation,
|
||||
ruleActions
|
||||
);
|
||||
if (isAttributeModified) {
|
||||
|
@ -566,7 +576,7 @@ async function getUpdatedAttributesFromOperations(
|
|||
|
||||
// TODO https://github.com/elastic/kibana/issues/148414
|
||||
// If any action-level frequencies get pushed into a SIEM rule, strip their frequencies
|
||||
const firstFrequency = operation.value[0]?.frequency;
|
||||
const firstFrequency = updatedOperation.value[0]?.frequency;
|
||||
if (rule.attributes.consumer === AlertConsumers.SIEM && firstFrequency) {
|
||||
ruleActions.actions = ruleActions.actions.map((action) => omit(action, 'frequency'));
|
||||
if (!attributes.notifyWhen) {
|
||||
|
|
|
@ -11,16 +11,15 @@ import { AlertConsumers } from '@kbn/rule-data-utils';
|
|||
import { SavedObjectsUtils } from '@kbn/core/server';
|
||||
import { withSpan } from '@kbn/apm-utils';
|
||||
import { parseDuration } from '../../../common/parse_duration';
|
||||
import { RawRule, SanitizedRule, RuleTypeParams, RuleAction, Rule } from '../../types';
|
||||
import { RawRule, SanitizedRule, RuleTypeParams, Rule } from '../../types';
|
||||
import { WriteOperations, AlertingAuthorizationEntity } from '../../authorization';
|
||||
import { validateRuleTypeParams, getRuleNotifyWhenType, getDefaultMonitoring } from '../../lib';
|
||||
import { getRuleExecutionStatusPending } from '../../lib/rule_execution_status';
|
||||
import { createRuleSavedObject, extractReferences, validateActions } from '../lib';
|
||||
import { createRuleSavedObject, extractReferences, validateActions, addUuid } from '../lib';
|
||||
import { generateAPIKeyName, getMappedParams, apiKeyAsAlertAttributes } from '../common';
|
||||
import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { NormalizedAlertAction, RulesClientContext } from '../types';
|
||||
|
||||
type NormalizedAlertAction = Omit<RuleAction, 'actionTypeId'>;
|
||||
interface SavedObjectOptions {
|
||||
id?: string;
|
||||
migrationVersion?: Record<string, string>;
|
||||
|
@ -51,8 +50,10 @@ export interface CreateOptions<Params extends RuleTypeParams> {
|
|||
|
||||
export async function create<Params extends RuleTypeParams = never>(
|
||||
context: RulesClientContext,
|
||||
{ data, options, allowMissingConnectorSecrets }: CreateOptions<Params>
|
||||
{ data: initialData, options, allowMissingConnectorSecrets }: CreateOptions<Params>
|
||||
): Promise<SanitizedRule<Params>> {
|
||||
const data = { ...initialData, actions: addUuid(initialData.actions) };
|
||||
|
||||
const id = options?.id || SavedObjectsUtils.generateId();
|
||||
|
||||
try {
|
||||
|
@ -105,7 +106,6 @@ export async function create<Params extends RuleTypeParams = never>(
|
|||
}
|
||||
}
|
||||
|
||||
await validateActions(context, ruleType, data, allowMissingConnectorSecrets);
|
||||
await withSpan({ name: 'validateActions', type: 'rules' }, () =>
|
||||
validateActions(context, ruleType, data, allowMissingConnectorSecrets)
|
||||
);
|
||||
|
|
|
@ -24,7 +24,13 @@ import { bulkMarkApiKeysForInvalidation } from '../../invalidate_pending_api_key
|
|||
import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events';
|
||||
import { getMappedParams } from '../common/mapped_params_utils';
|
||||
import { NormalizedAlertAction, RulesClientContext } from '../types';
|
||||
import { validateActions, extractReferences, updateMeta, getPartialRuleFromRaw } from '../lib';
|
||||
import {
|
||||
validateActions,
|
||||
extractReferences,
|
||||
updateMeta,
|
||||
getPartialRuleFromRaw,
|
||||
addUuid,
|
||||
} from '../lib';
|
||||
import { generateAPIKeyName, apiKeyAsAlertAttributes } from '../common';
|
||||
|
||||
export interface UpdateOptions<Params extends RuleTypeParams> {
|
||||
|
@ -143,9 +149,11 @@ async function updateWithOCC<Params extends RuleTypeParams>(
|
|||
|
||||
async function updateAlert<Params extends RuleTypeParams>(
|
||||
context: RulesClientContext,
|
||||
{ id, data, allowMissingConnectorSecrets }: UpdateOptions<Params>,
|
||||
{ id, data: initialData, allowMissingConnectorSecrets }: UpdateOptions<Params>,
|
||||
{ attributes, version }: SavedObject<RawRule>
|
||||
): Promise<PartialRule<Params>> {
|
||||
const data = { ...initialData, actions: addUuid(initialData.actions) };
|
||||
|
||||
const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId);
|
||||
|
||||
// TODO https://github.com/elastic/kibana/issues/148414
|
||||
|
|
|
@ -20,6 +20,7 @@ import { ActionsAuthorization, ActionsClient } from '@kbn/actions-plugin/server'
|
|||
import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
import { bulkMarkApiKeysForInvalidation } from '../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation';
|
||||
import { NormalizedAlertAction } from '../types';
|
||||
|
||||
jest.mock('../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation', () => ({
|
||||
bulkMarkApiKeysForInvalidation: jest.fn(),
|
||||
|
@ -29,6 +30,11 @@ jest.mock('../../lib/snooze/is_snooze_active', () => ({
|
|||
isSnoozeActive: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('uuid', () => {
|
||||
let uuid = 100;
|
||||
return { v4: () => `${uuid++}` };
|
||||
});
|
||||
|
||||
const { isSnoozeActive } = jest.requireMock('../../lib/snooze/is_snooze_active');
|
||||
|
||||
const taskManager = taskManagerMock.createStart();
|
||||
|
@ -115,7 +121,29 @@ describe('bulkEdit()', () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
rulesClient = new RulesClient(rulesClientParams);
|
||||
|
||||
actionsClient = (await rulesClientParams.getActionsClient()) as jest.Mocked<ActionsClient>;
|
||||
actionsClient.getBulk.mockReset();
|
||||
actionsClient.getBulk.mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
actionTypeId: 'test',
|
||||
config: {
|
||||
from: 'me@me.com',
|
||||
hasAuth: false,
|
||||
host: 'hello',
|
||||
port: 22,
|
||||
secure: null,
|
||||
service: null,
|
||||
},
|
||||
isMissingSecrets: false,
|
||||
name: 'email connector',
|
||||
isPreconfigured: false,
|
||||
isDeprecated: false,
|
||||
},
|
||||
]);
|
||||
rulesClientParams.getActionsClient.mockResolvedValue(actionsClient);
|
||||
|
||||
authorization.getFindAuthorizationFilter.mockResolvedValue({
|
||||
ensureRuleTypeIsAuthorized() {},
|
||||
});
|
||||
|
@ -426,6 +454,146 @@ describe('bulkEdit()', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('actions operations', () => {
|
||||
beforeEach(() => {
|
||||
mockCreatePointInTimeFinderAsInternalUser({
|
||||
saved_objects: [existingDecryptedRule],
|
||||
});
|
||||
});
|
||||
|
||||
test('should add uuid to new actions', async () => {
|
||||
const existingAction = {
|
||||
frequency: {
|
||||
notifyWhen: 'onActiveAlert',
|
||||
summary: false,
|
||||
throttle: null,
|
||||
},
|
||||
group: 'default',
|
||||
id: '1',
|
||||
params: {},
|
||||
uuid: '111',
|
||||
};
|
||||
const newAction = {
|
||||
frequency: {
|
||||
notifyWhen: 'onActiveAlert',
|
||||
summary: false,
|
||||
throttle: null,
|
||||
},
|
||||
group: 'default',
|
||||
id: '2',
|
||||
params: {},
|
||||
};
|
||||
const newAction2 = {
|
||||
frequency: {
|
||||
notifyWhen: 'onActiveAlert',
|
||||
summary: false,
|
||||
throttle: null,
|
||||
},
|
||||
group: 'default',
|
||||
id: '3',
|
||||
params: {},
|
||||
};
|
||||
|
||||
unsecuredSavedObjectsClient.bulkCreate.mockResolvedValue({
|
||||
saved_objects: [
|
||||
{
|
||||
...existingRule,
|
||||
attributes: {
|
||||
...existingRule.attributes,
|
||||
actions: [
|
||||
{
|
||||
...existingAction,
|
||||
actionRef: 'action_0',
|
||||
},
|
||||
{
|
||||
...newAction,
|
||||
actionRef: 'action_1',
|
||||
uuid: '222',
|
||||
},
|
||||
],
|
||||
},
|
||||
references: [
|
||||
{
|
||||
name: 'action_0',
|
||||
type: 'action',
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
name: 'action_1',
|
||||
type: 'action',
|
||||
id: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const result = await rulesClient.bulkEdit({
|
||||
filter: '',
|
||||
operations: [
|
||||
{
|
||||
field: 'actions',
|
||||
operation: 'add',
|
||||
value: [existingAction, newAction, newAction2] as NormalizedAlertAction[],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(unsecuredSavedObjectsClient.bulkCreate).toHaveBeenCalledWith(
|
||||
[
|
||||
{
|
||||
...existingRule,
|
||||
attributes: {
|
||||
...existingRule.attributes,
|
||||
actions: [
|
||||
{
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test',
|
||||
frequency: { notifyWhen: 'onActiveAlert', summary: false, throttle: null },
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: '111',
|
||||
},
|
||||
{
|
||||
actionRef: '',
|
||||
actionTypeId: '',
|
||||
frequency: { notifyWhen: 'onActiveAlert', summary: false, throttle: null },
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: '100',
|
||||
},
|
||||
{
|
||||
actionRef: '',
|
||||
actionTypeId: '',
|
||||
frequency: { notifyWhen: 'onActiveAlert', summary: false, throttle: null },
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: '101',
|
||||
},
|
||||
],
|
||||
apiKey: null,
|
||||
apiKeyOwner: null,
|
||||
meta: { versionApiKeyLastmodified: 'v8.2.0' },
|
||||
name: 'my rule name',
|
||||
enabled: false,
|
||||
updatedAt: '2019-02-12T21:01:22.479Z',
|
||||
updatedBy: 'elastic',
|
||||
tags: ['foo'],
|
||||
},
|
||||
references: [{ id: '1', name: 'action_0', type: 'action' }],
|
||||
},
|
||||
],
|
||||
{ overwrite: true }
|
||||
);
|
||||
expect(result.rules[0]).toEqual({
|
||||
...existingRule.attributes,
|
||||
actions: [existingAction, { ...newAction, uuid: '222' }],
|
||||
id: existingRule.id,
|
||||
snoozeSchedule: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('index pattern operations', () => {
|
||||
beforeEach(() => {
|
||||
mockCreatePointInTimeFinderAsInternalUser({
|
||||
|
|
|
@ -38,6 +38,11 @@ jest.mock('@kbn/core-saved-objects-utils-server', () => {
|
|||
};
|
||||
});
|
||||
|
||||
jest.mock('uuid', () => {
|
||||
let uuid = 100;
|
||||
return { v4: () => `${uuid++}` };
|
||||
});
|
||||
|
||||
const taskManager = taskManagerMock.createStart();
|
||||
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
||||
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||
|
@ -406,6 +411,7 @@ describe('create()', () => {
|
|||
"params": Object {
|
||||
"foo": true,
|
||||
},
|
||||
"uuid": "102",
|
||||
},
|
||||
],
|
||||
"alertTypeId": "123",
|
||||
|
@ -624,6 +630,7 @@ describe('create()', () => {
|
|||
"params": Object {
|
||||
"foo": true,
|
||||
},
|
||||
"uuid": "104",
|
||||
},
|
||||
],
|
||||
"alertTypeId": "123",
|
||||
|
@ -1053,6 +1060,7 @@ describe('create()', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '108',
|
||||
},
|
||||
{
|
||||
group: 'default',
|
||||
|
@ -1061,6 +1069,7 @@ describe('create()', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '109',
|
||||
},
|
||||
{
|
||||
group: 'default',
|
||||
|
@ -1069,6 +1078,7 @@ describe('create()', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '110',
|
||||
},
|
||||
],
|
||||
alertTypeId: '123',
|
||||
|
@ -1272,7 +1282,13 @@ describe('create()', () => {
|
|||
'alert',
|
||||
{
|
||||
actions: [
|
||||
{ actionRef: 'action_0', actionTypeId: 'test', group: 'default', params: { foo: true } },
|
||||
{
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test',
|
||||
group: 'default',
|
||||
params: { foo: true },
|
||||
uuid: '112',
|
||||
},
|
||||
],
|
||||
alertTypeId: '123',
|
||||
apiKey: null,
|
||||
|
@ -1445,7 +1461,13 @@ describe('create()', () => {
|
|||
'alert',
|
||||
{
|
||||
actions: [
|
||||
{ actionRef: 'action_0', actionTypeId: 'test', group: 'default', params: { foo: true } },
|
||||
{
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test',
|
||||
group: 'default',
|
||||
params: { foo: true },
|
||||
uuid: '113',
|
||||
},
|
||||
],
|
||||
alertTypeId: '123',
|
||||
apiKey: null,
|
||||
|
@ -1612,6 +1634,7 @@ describe('create()', () => {
|
|||
group: 'default',
|
||||
actionTypeId: 'test',
|
||||
params: { foo: true },
|
||||
uuid: '115',
|
||||
},
|
||||
],
|
||||
alertTypeId: '123',
|
||||
|
@ -1747,6 +1770,7 @@ describe('create()', () => {
|
|||
group: 'default',
|
||||
actionTypeId: 'test',
|
||||
params: { foo: true },
|
||||
uuid: '116',
|
||||
},
|
||||
],
|
||||
legacyId: null,
|
||||
|
@ -1882,6 +1906,7 @@ describe('create()', () => {
|
|||
group: 'default',
|
||||
actionTypeId: 'test',
|
||||
params: { foo: true },
|
||||
uuid: '117',
|
||||
},
|
||||
],
|
||||
legacyId: null,
|
||||
|
@ -2044,6 +2069,7 @@ describe('create()', () => {
|
|||
},
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test',
|
||||
uuid: '118',
|
||||
},
|
||||
],
|
||||
apiKeyOwner: null,
|
||||
|
@ -2409,6 +2435,7 @@ describe('create()', () => {
|
|||
group: 'default',
|
||||
actionTypeId: 'test',
|
||||
params: { foo: true },
|
||||
uuid: '126',
|
||||
},
|
||||
],
|
||||
alertTypeId: '123',
|
||||
|
@ -2513,6 +2540,7 @@ describe('create()', () => {
|
|||
group: 'default',
|
||||
actionTypeId: 'test',
|
||||
params: { foo: true },
|
||||
uuid: '127',
|
||||
},
|
||||
],
|
||||
legacyId: null,
|
||||
|
|
|
@ -37,6 +37,11 @@ jest.mock('../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation
|
|||
bulkMarkApiKeysForInvalidation: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('uuid', () => {
|
||||
let uuid = 100;
|
||||
return { v4: () => `${uuid++}` };
|
||||
});
|
||||
|
||||
const bulkMarkApiKeysForInvalidationMock = bulkMarkApiKeysForInvalidation as jest.Mock;
|
||||
const taskManager = taskManagerMock.createStart();
|
||||
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
||||
|
@ -350,6 +355,7 @@ describe('update()', () => {
|
|||
"params": Object {
|
||||
"foo": true,
|
||||
},
|
||||
"uuid": "100",
|
||||
},
|
||||
Object {
|
||||
"actionRef": "action_1",
|
||||
|
@ -358,6 +364,7 @@ describe('update()', () => {
|
|||
"params": Object {
|
||||
"foo": true,
|
||||
},
|
||||
"uuid": "101",
|
||||
},
|
||||
Object {
|
||||
"actionRef": "action_2",
|
||||
|
@ -366,6 +373,7 @@ describe('update()', () => {
|
|||
"params": Object {
|
||||
"foo": true,
|
||||
},
|
||||
"uuid": "102",
|
||||
},
|
||||
],
|
||||
"alertTypeId": "myType",
|
||||
|
@ -585,6 +593,7 @@ describe('update()', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '103',
|
||||
},
|
||||
{
|
||||
group: 'default',
|
||||
|
@ -593,6 +602,7 @@ describe('update()', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '104',
|
||||
},
|
||||
{
|
||||
group: 'custom',
|
||||
|
@ -601,6 +611,7 @@ describe('update()', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '105',
|
||||
},
|
||||
],
|
||||
alertTypeId: 'myType',
|
||||
|
@ -779,7 +790,13 @@ describe('update()', () => {
|
|||
'alert',
|
||||
{
|
||||
actions: [
|
||||
{ actionRef: 'action_0', actionTypeId: 'test', group: 'default', params: { foo: true } },
|
||||
{
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test',
|
||||
group: 'default',
|
||||
params: { foo: true },
|
||||
uuid: '106',
|
||||
},
|
||||
],
|
||||
alertTypeId: 'myType',
|
||||
apiKey: null,
|
||||
|
@ -953,6 +970,7 @@ describe('update()', () => {
|
|||
"params": Object {
|
||||
"foo": true,
|
||||
},
|
||||
"uuid": "107",
|
||||
},
|
||||
],
|
||||
"alertTypeId": "myType",
|
||||
|
@ -1101,6 +1119,7 @@ describe('update()', () => {
|
|||
"params": Object {
|
||||
"foo": true,
|
||||
},
|
||||
"uuid": "108",
|
||||
},
|
||||
],
|
||||
"alertTypeId": "myType",
|
||||
|
@ -2113,6 +2132,7 @@ describe('update()', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '144',
|
||||
},
|
||||
],
|
||||
alertTypeId: 'myType',
|
||||
|
@ -2522,4 +2542,166 @@ describe('update()', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('updates an action with uuid and adds uuid to an action without it', async () => {
|
||||
actionsClient.getBulk.mockReset();
|
||||
actionsClient.getBulk.mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
actionTypeId: 'test',
|
||||
config: {
|
||||
from: 'me@me.com',
|
||||
hasAuth: false,
|
||||
host: 'hello',
|
||||
port: 22,
|
||||
secure: null,
|
||||
service: null,
|
||||
},
|
||||
isMissingSecrets: false,
|
||||
name: 'email connector',
|
||||
isPreconfigured: false,
|
||||
isDeprecated: false,
|
||||
},
|
||||
]);
|
||||
unsecuredSavedObjectsClient.create.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
enabled: true,
|
||||
schedule: { interval: '1m' },
|
||||
params: {
|
||||
bar: true,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
group: 'default',
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test',
|
||||
params: {
|
||||
foo: true,
|
||||
},
|
||||
frequency: {
|
||||
notifyWhen: 'onActiveAlert',
|
||||
throttle: null,
|
||||
summary: false,
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
{
|
||||
group: 'default',
|
||||
actionRef: 'action_1',
|
||||
actionTypeId: 'test',
|
||||
params: {
|
||||
foo: true,
|
||||
},
|
||||
frequency: {
|
||||
notifyWhen: 'onActiveAlert',
|
||||
throttle: null,
|
||||
summary: false,
|
||||
},
|
||||
uuid: '111-111',
|
||||
},
|
||||
],
|
||||
scheduledTaskId: 'task-123',
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
references: [
|
||||
{
|
||||
name: 'action_0',
|
||||
type: 'action',
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
name: 'action_1',
|
||||
type: 'action',
|
||||
id: '2',
|
||||
},
|
||||
],
|
||||
});
|
||||
await rulesClient.update({
|
||||
id: '1',
|
||||
data: {
|
||||
schedule: { interval: '1m' },
|
||||
name: 'abc',
|
||||
tags: ['foo'],
|
||||
params: {
|
||||
bar: true,
|
||||
risk_score: 40,
|
||||
severity: 'low',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
group: 'default',
|
||||
id: '1',
|
||||
params: {
|
||||
foo: true,
|
||||
},
|
||||
frequency: {
|
||||
notifyWhen: 'onActiveAlert',
|
||||
throttle: null,
|
||||
summary: false,
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
{
|
||||
group: 'default',
|
||||
id: '2',
|
||||
params: {
|
||||
foo: true,
|
||||
},
|
||||
frequency: {
|
||||
notifyWhen: 'onActiveAlert',
|
||||
throttle: null,
|
||||
summary: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith(
|
||||
'alert',
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test',
|
||||
frequency: { notifyWhen: 'onActiveAlert', summary: false, throttle: null },
|
||||
group: 'default',
|
||||
params: { foo: true },
|
||||
uuid: '123-456',
|
||||
},
|
||||
{
|
||||
actionRef: '',
|
||||
actionTypeId: '',
|
||||
frequency: { notifyWhen: 'onActiveAlert', summary: false, throttle: null },
|
||||
group: 'default',
|
||||
params: { foo: true },
|
||||
uuid: '151',
|
||||
},
|
||||
],
|
||||
alertTypeId: 'myType',
|
||||
apiKey: null,
|
||||
apiKeyOwner: null,
|
||||
consumer: 'myApp',
|
||||
enabled: true,
|
||||
mapped_params: { risk_score: 40, severity: '20-low' },
|
||||
meta: { versionApiKeyLastmodified: 'v7.10.0' },
|
||||
name: 'abc',
|
||||
notifyWhen: null,
|
||||
params: { bar: true, risk_score: 40, severity: 'low' },
|
||||
schedule: { interval: '1m' },
|
||||
scheduledTaskId: 'task-123',
|
||||
tags: ['foo'],
|
||||
updatedAt: '2019-02-12T21:01:22.479Z',
|
||||
updatedBy: 'elastic',
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
overwrite: true,
|
||||
references: [{ id: '1', name: 'action_0', type: 'action' }],
|
||||
version: '123',
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -73,6 +73,10 @@ export interface RulesClientContext {
|
|||
|
||||
export type NormalizedAlertAction = Omit<RuleAction, 'actionTypeId'>;
|
||||
|
||||
export type NormalizedAlertActionWithUuid = Omit<RuleAction, 'actionTypeId' | 'uuid'> & {
|
||||
uuid: string;
|
||||
};
|
||||
|
||||
export interface RegistryAlertTypeWithAuth extends RegistryRuleType {
|
||||
authorizedConsumers: string[];
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ export const alertMappings: SavedObjectsTypeMappingDefinition = {
|
|||
type: 'keyword',
|
||||
},
|
||||
actions: {
|
||||
dynamic: false,
|
||||
type: 'nested',
|
||||
properties: {
|
||||
group: {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { SavedObjectUnsanitizedDoc } from '@kbn/core-saved-objects-server';
|
||||
import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { extractedSavedObjectParamReferenceNamePrefix } from '../../../rules_client/common/constants';
|
||||
import {
|
||||
createEsoMigration,
|
||||
|
@ -37,6 +38,27 @@ function addGroupByToEsQueryRule(
|
|||
return doc;
|
||||
}
|
||||
|
||||
function addActionUuid(
|
||||
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||
const {
|
||||
attributes: { actions },
|
||||
} = doc;
|
||||
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
actions: actions
|
||||
? actions.map((action) => ({
|
||||
...action,
|
||||
uuid: uuidv4(),
|
||||
}))
|
||||
: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function addLogViewRefToLogThresholdRule(
|
||||
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||
|
@ -94,5 +116,10 @@ export const getMigrations870 = (encryptedSavedObjects: EncryptedSavedObjectsPlu
|
|||
createEsoMigration(
|
||||
encryptedSavedObjects,
|
||||
(doc: SavedObjectUnsanitizedDoc<RawRule>): doc is SavedObjectUnsanitizedDoc<RawRule> => true,
|
||||
pipeMigrations(addGroupByToEsQueryRule, addLogViewRefToLogThresholdRule, addOutcomeOrder)
|
||||
pipeMigrations(
|
||||
addGroupByToEsQueryRule,
|
||||
addLogViewRefToLogThresholdRule,
|
||||
addOutcomeOrder,
|
||||
addActionUuid
|
||||
)
|
||||
);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import sinon from 'sinon';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { getMigrations } from '.';
|
||||
import { RawRule } from '../../types';
|
||||
import { RawRule, RawRuleAction } from '../../types';
|
||||
import { SavedObjectMigrationContext, SavedObjectUnsanitizedDoc } from '@kbn/core/server';
|
||||
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
|
||||
import { migrationMocks } from '@kbn/core/server/mocks';
|
||||
|
@ -2628,6 +2628,28 @@ describe('successful migrations', () => {
|
|||
outcomeOrder: 0,
|
||||
});
|
||||
});
|
||||
|
||||
test('adds uuid to rule actions', () => {
|
||||
const migration870 = getMigrations(encryptedSavedObjectsSetup, {}, isPreconfigured)['8.7.0'];
|
||||
const rule = getMockData(
|
||||
{
|
||||
params: { foo: true },
|
||||
alertTypeId: '.not-es-query',
|
||||
},
|
||||
true
|
||||
);
|
||||
const migratedAlert870 = migration870(rule, migrationContext);
|
||||
|
||||
expect(migratedAlert870.attributes.actions).toEqual([
|
||||
{
|
||||
group: 'default',
|
||||
actionRef: '1',
|
||||
actionTypeId: '1',
|
||||
params: { foo: true },
|
||||
uuid: expect.stringMatching(/.*\S.*/), // non-empty string
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Metrics Inventory Threshold rule', () => {
|
||||
|
@ -2974,7 +2996,7 @@ function getMockData(
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
},
|
||||
} as unknown as RawRuleAction,
|
||||
],
|
||||
...overwrites,
|
||||
},
|
||||
|
|
|
@ -50,6 +50,7 @@ export const RULE_ACTIONS = [
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '111-111',
|
||||
},
|
||||
{
|
||||
actionTypeId: 'action',
|
||||
|
@ -58,6 +59,7 @@ export const RULE_ACTIONS = [
|
|||
params: {
|
||||
isResolved: true,
|
||||
},
|
||||
uuid: '222-222',
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -190,6 +192,7 @@ export const mockedRuleTypeSavedObject: Rule<RuleTypeParams> = {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '111-111',
|
||||
},
|
||||
{
|
||||
group: RecoveredActionGroup.id,
|
||||
|
@ -198,6 +201,7 @@ export const mockedRuleTypeSavedObject: Rule<RuleTypeParams> = {
|
|||
params: {
|
||||
isResolved: true,
|
||||
},
|
||||
uuid: '222-222',
|
||||
},
|
||||
],
|
||||
executionStatus: {
|
||||
|
|
|
@ -20,6 +20,7 @@ const mockOldAction: RuleAction = {
|
|||
group: 'default',
|
||||
actionTypeId: 'slack',
|
||||
params: {},
|
||||
uuid: '123-456',
|
||||
};
|
||||
|
||||
const mockAction: RuleAction = {
|
||||
|
@ -32,6 +33,7 @@ const mockAction: RuleAction = {
|
|||
notifyWhen: 'onActiveAlert',
|
||||
throttle: null,
|
||||
},
|
||||
uuid: '123-456',
|
||||
};
|
||||
|
||||
const mockSummaryAction: RuleAction = {
|
||||
|
|
|
@ -1284,6 +1284,7 @@ describe('Task Runner', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '111-111',
|
||||
},
|
||||
{
|
||||
group: recoveryActionGroup.id,
|
||||
|
@ -1292,6 +1293,7 @@ describe('Task Runner', () => {
|
|||
params: {
|
||||
isResolved: true,
|
||||
},
|
||||
uuid: '222-222',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -1388,6 +1390,7 @@ describe('Task Runner', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '111-111',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -1464,6 +1467,7 @@ describe('Task Runner', () => {
|
|||
params: {
|
||||
foo: true,
|
||||
},
|
||||
uuid: '111-111',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -235,6 +235,7 @@ export type UntypedRuleType = RuleType<
|
|||
>;
|
||||
|
||||
export interface RawRuleAction extends SavedObjectAttributes {
|
||||
uuid: string;
|
||||
group: string;
|
||||
actionRef: string;
|
||||
actionTypeId: string;
|
||||
|
|
|
@ -36,6 +36,7 @@ describe('transform_actions', () => {
|
|||
group: 'group',
|
||||
actionTypeId: 'actionTypeId',
|
||||
params: {},
|
||||
uuid: '111',
|
||||
};
|
||||
const ruleAction = transformAlertToRuleAction(alertAction);
|
||||
expect(ruleAction).toEqual({
|
||||
|
@ -43,6 +44,7 @@ describe('transform_actions', () => {
|
|||
group: alertAction.group,
|
||||
action_type_id: alertAction.actionTypeId,
|
||||
params: alertAction.params,
|
||||
uuid: '111',
|
||||
});
|
||||
});
|
||||
test('it should transform ResponseAction[] to RuleResponseAction[]', () => {
|
||||
|
|
|
@ -12,13 +12,15 @@ import type { RuleAlertAction } from './types';
|
|||
export const transformRuleToAlertAction = ({
|
||||
group,
|
||||
id,
|
||||
action_type_id, // eslint-disable-line @typescript-eslint/naming-convention
|
||||
action_type_id: actionTypeId,
|
||||
params,
|
||||
uuid,
|
||||
}: RuleAlertAction): RuleAction => ({
|
||||
group,
|
||||
id,
|
||||
params,
|
||||
actionTypeId: action_type_id,
|
||||
actionTypeId,
|
||||
...(uuid && { uuid }),
|
||||
});
|
||||
|
||||
export const transformAlertToRuleAction = ({
|
||||
|
@ -26,11 +28,13 @@ export const transformAlertToRuleAction = ({
|
|||
id,
|
||||
actionTypeId,
|
||||
params,
|
||||
uuid,
|
||||
}: RuleAction): RuleAlertAction => ({
|
||||
group,
|
||||
id,
|
||||
params,
|
||||
action_type_id: actionTypeId,
|
||||
...(uuid && { uuid }),
|
||||
});
|
||||
|
||||
export const transformRuleToAlertResponseAction = ({
|
||||
|
|
|
@ -43,6 +43,7 @@ describe('cloneRule', () => {
|
|||
summary: false,
|
||||
},
|
||||
connector_type_id: '.server-log',
|
||||
uuid: '123456',
|
||||
},
|
||||
],
|
||||
scheduled_task_id: '1',
|
||||
|
@ -74,6 +75,7 @@ describe('cloneRule', () => {
|
|||
"level": "info",
|
||||
"message": "alert ",
|
||||
},
|
||||
"uuid": "123456",
|
||||
},
|
||||
],
|
||||
"activeSnoozes": undefined,
|
||||
|
|
|
@ -9,6 +9,7 @@ import { AsApiContract, RewriteRequestCase } from '@kbn/actions-plugin/common';
|
|||
import { Rule, RuleAction, ResolvedRule, RuleLastRun } from '../../../types';
|
||||
|
||||
const transformAction: RewriteRequestCase<RuleAction> = ({
|
||||
uuid,
|
||||
group,
|
||||
id,
|
||||
connector_type_id: actionTypeId,
|
||||
|
@ -28,6 +29,7 @@ const transformAction: RewriteRequestCase<RuleAction> = ({
|
|||
},
|
||||
}
|
||||
: {}),
|
||||
...(uuid && { uuid }),
|
||||
});
|
||||
|
||||
const transformExecutionStatus: RewriteRequestCase<RuleExecutionStatus> = ({
|
||||
|
|
|
@ -17,7 +17,7 @@ type RuleUpdatesBody = Pick<
|
|||
>;
|
||||
const rewriteBodyRequest: RewriteResponseCase<RuleUpdatesBody> = ({ actions, ...res }): any => ({
|
||||
...res,
|
||||
actions: actions.map(({ group, id, params, frequency }) => ({
|
||||
actions: actions.map(({ group, id, params, frequency, uuid }) => ({
|
||||
group,
|
||||
id,
|
||||
params,
|
||||
|
@ -26,6 +26,7 @@ const rewriteBodyRequest: RewriteResponseCase<RuleUpdatesBody> = ({ actions, ...
|
|||
throttle: frequency!.throttle,
|
||||
summary: frequency!.summary,
|
||||
},
|
||||
...(uuid && { uuid }),
|
||||
})),
|
||||
});
|
||||
|
||||
|
|
|
@ -345,6 +345,7 @@ describe('getRuleWithInvalidatedFields', () => {
|
|||
field: {},
|
||||
},
|
||||
},
|
||||
uuid: '123-456',
|
||||
},
|
||||
],
|
||||
tags: [],
|
||||
|
@ -390,6 +391,7 @@ describe('getRuleWithInvalidatedFields', () => {
|
|||
field: {},
|
||||
},
|
||||
},
|
||||
uuid: '111-111',
|
||||
},
|
||||
{
|
||||
actionTypeId: 'test',
|
||||
|
@ -402,6 +404,7 @@ describe('getRuleWithInvalidatedFields', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
uuid: '222-222',
|
||||
},
|
||||
],
|
||||
tags: [],
|
||||
|
|
|
@ -45,6 +45,7 @@ describe('connectors_selection', () => {
|
|||
group: 'group',
|
||||
class: 'test class',
|
||||
},
|
||||
uuid: '123-456',
|
||||
};
|
||||
|
||||
const actionTypeIndex: Record<string, ActionType> = {
|
||||
|
|
|
@ -111,6 +111,7 @@ describe('rule reducer', () => {
|
|||
actionTypeId: 'testId',
|
||||
group: 'Rule',
|
||||
params: {},
|
||||
uuid: '123-456',
|
||||
});
|
||||
const updatedRule = ruleReducer(
|
||||
{ rule: initialRule },
|
||||
|
@ -151,6 +152,7 @@ describe('rule reducer', () => {
|
|||
params: {
|
||||
testActionParam: 'some value',
|
||||
},
|
||||
uuid: '123-456',
|
||||
});
|
||||
const updatedRule = ruleReducer(
|
||||
{ rule: initialRule },
|
||||
|
@ -172,6 +174,7 @@ describe('rule reducer', () => {
|
|||
actionTypeId: 'testId',
|
||||
group: 'Rule',
|
||||
params: {},
|
||||
uuid: '123-456',
|
||||
});
|
||||
const updatedRule = ruleReducer(
|
||||
{ rule: initialRule },
|
||||
|
@ -193,6 +196,7 @@ describe('rule reducer', () => {
|
|||
actionTypeId: 'testId',
|
||||
group: 'Rule',
|
||||
params: {},
|
||||
uuid: '123-456',
|
||||
});
|
||||
const updatedRule = ruleReducer(
|
||||
{ rule: initialRule },
|
||||
|
|
|
@ -106,6 +106,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
|||
connector_type_id: createdAction.connector_type_id,
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: response.body.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
enabled: true,
|
||||
|
|
|
@ -321,6 +321,7 @@ const findTestUtils = (
|
|||
group: 'default',
|
||||
connector_type_id: 'test.noop',
|
||||
params: {},
|
||||
uuid: createdAlert.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
params: {},
|
||||
|
|
|
@ -74,12 +74,13 @@ export default function alertTests({ getService }: FtrProviderContext) {
|
|||
updatedBy: user.fullName,
|
||||
actions: actions.map((action: any) => {
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
const { connector_type_id, group, id, params } = action;
|
||||
const { connector_type_id, group, id, params, uuid } = action;
|
||||
return {
|
||||
actionTypeId: connector_type_id,
|
||||
group,
|
||||
id,
|
||||
params,
|
||||
uuid,
|
||||
};
|
||||
}),
|
||||
producer: 'alertsFixture',
|
||||
|
@ -421,12 +422,13 @@ instanceStateValue: true
|
|||
updatedBy: Superuser.fullName,
|
||||
actions: response2.body.actions.map((action: any) => {
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
const { connector_type_id, group, id, params } = action;
|
||||
const { connector_type_id, group, id, params, uuid } = action;
|
||||
return {
|
||||
actionTypeId: connector_type_id,
|
||||
group,
|
||||
id,
|
||||
params,
|
||||
uuid,
|
||||
};
|
||||
}),
|
||||
producer: 'alertsFixture',
|
||||
|
|
|
@ -127,6 +127,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
|
|||
connector_type_id: 'test.noop',
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: response.body.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
scheduled_task_id: createdAlert.scheduled_task_id,
|
||||
|
|
|
@ -116,6 +116,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
|
|||
group: 'default',
|
||||
params: {},
|
||||
connector_type_id: 'test.noop',
|
||||
uuid: response.body.rules[0].actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
|
|
|
@ -145,6 +145,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
|||
connector_type_id: response.body.actions[0].connector_type_id,
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: response.body.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
enabled: true,
|
||||
|
|
|
@ -113,12 +113,13 @@ export function alertTests({ getService }: FtrProviderContext, space: Space) {
|
|||
updatedBy: null,
|
||||
actions: response.body.actions.map((action: any) => {
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
const { connector_type_id, group, id, params } = action;
|
||||
const { connector_type_id, group, id, params, uuid } = action;
|
||||
return {
|
||||
actionTypeId: connector_type_id,
|
||||
group,
|
||||
id,
|
||||
params,
|
||||
uuid,
|
||||
};
|
||||
}),
|
||||
producer: 'alertsFixture',
|
||||
|
|
|
@ -76,6 +76,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
|||
connector_type_id: createdAction.connector_type_id,
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: response.body.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
enabled: true,
|
||||
|
@ -169,6 +170,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
|||
connector_type_id: createdAction.connector_type_id,
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: response.body.actions[0].uuid,
|
||||
},
|
||||
{
|
||||
id: 'my-slack1',
|
||||
|
@ -177,6 +179,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
|||
params: {
|
||||
message: 'something important happened!',
|
||||
},
|
||||
uuid: response.body.actions[1].uuid,
|
||||
},
|
||||
],
|
||||
enabled: true,
|
||||
|
@ -219,6 +222,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
|||
actionTypeId: 'test.noop',
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: rawActions[0].uuid,
|
||||
},
|
||||
{
|
||||
actionRef: 'preconfigured:my-slack1',
|
||||
|
@ -227,6 +231,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
|||
params: {
|
||||
message: 'something important happened!',
|
||||
},
|
||||
uuid: rawActions[1].uuid,
|
||||
},
|
||||
]);
|
||||
|
||||
|
@ -479,6 +484,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
|||
actionTypeId: createdAction.connector_type_id,
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: response.body.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
enabled: true,
|
||||
|
|
|
@ -102,6 +102,7 @@ const findTestUtils = (
|
|||
notify_when: 'onThrottleInterval',
|
||||
throttle: '1m',
|
||||
},
|
||||
uuid: match.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
params: {},
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import expect from 'expect';
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import type { RawRule, RawRuleAction } from '@kbn/alerting-plugin/server/types';
|
||||
import { FILEBEAT_7X_INDICATOR_PATH } from '@kbn/alerting-plugin/server/saved_objects/migrations';
|
||||
|
@ -33,8 +33,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
`${getUrlPrefix(``)}/api/alerting/rule/74f3e6d7-b7bb-477d-ac28-92ee22728e6e`
|
||||
);
|
||||
|
||||
expect(response.status).to.eql(200);
|
||||
expect(response.body.consumer).to.equal('alerts');
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.consumer).toEqual('alerts');
|
||||
});
|
||||
|
||||
it('7.10.0 migrates the `metrics` consumer to be the `infrastructure`', async () => {
|
||||
|
@ -42,8 +42,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
`${getUrlPrefix(``)}/api/alerting/rule/74f3e6d7-b7bb-477d-ac28-fdf248d5f2a4`
|
||||
);
|
||||
|
||||
expect(response.status).to.eql(200);
|
||||
expect(response.body.consumer).to.equal('infrastructure');
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body.consumer).toEqual('infrastructure');
|
||||
});
|
||||
|
||||
it('7.10.0 migrates PagerDuty actions to have a default dedupKey', async () => {
|
||||
|
@ -51,10 +51,10 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
`${getUrlPrefix(``)}/api/alerting/rule/b6087f72-994f-46fb-8120-c6e5c50d0f8f`
|
||||
);
|
||||
|
||||
expect(response.status).to.eql(200);
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
expect(response.body.actions).to.eql([
|
||||
{
|
||||
expect(response.body.actions).toEqual([
|
||||
expect.objectContaining({
|
||||
connector_type_id: '.pagerduty',
|
||||
id: 'a6a8ab7a-35cf-445e-ade3-215a029c2ee3',
|
||||
group: 'default',
|
||||
|
@ -63,8 +63,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
eventAction: 'trigger',
|
||||
summary: 'fired {{alertInstanceId}}',
|
||||
},
|
||||
},
|
||||
{
|
||||
}),
|
||||
expect.objectContaining({
|
||||
connector_type_id: '.pagerduty',
|
||||
id: 'a6a8ab7a-35cf-445e-ade3-215a029c2ee3',
|
||||
group: 'default',
|
||||
|
@ -74,8 +74,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
eventAction: 'resolve',
|
||||
summary: 'fired {{alertInstanceId}}',
|
||||
},
|
||||
},
|
||||
{
|
||||
}),
|
||||
expect.objectContaining({
|
||||
connector_type_id: '.pagerduty',
|
||||
id: 'a6a8ab7a-35cf-445e-ade3-215a029c2ee3',
|
||||
group: 'default',
|
||||
|
@ -85,7 +85,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
eventAction: 'resolve',
|
||||
summary: 'fired {{alertInstanceId}}',
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -94,8 +94,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
`${getUrlPrefix(``)}/api/alerting/rule/74f3e6d7-b7bb-477d-ac28-92ee22728e6e`
|
||||
);
|
||||
|
||||
expect(response.status).to.eql(200);
|
||||
expect(response.body.updated_at).to.eql('2020-06-17T15:35:39.839Z');
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body.updated_at).toEqual('2020-06-17T15:35:39.839Z');
|
||||
});
|
||||
|
||||
it('7.11.0 migrates alerts to contain `notifyWhen` field', async () => {
|
||||
|
@ -103,8 +103,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
`${getUrlPrefix(``)}/api/alerting/rule/74f3e6d7-b7bb-477d-ac28-92ee22728e6e`
|
||||
);
|
||||
|
||||
expect(response.status).to.eql(200);
|
||||
expect(response.body.notify_when).to.eql('onActiveAlert');
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body.notify_when).toEqual('onActiveAlert');
|
||||
});
|
||||
|
||||
it('7.11.2 migrates alerts with case actions, case fields are nested in an incident object', async () => {
|
||||
|
@ -112,9 +112,9 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
`${getUrlPrefix(``)}/api/alerting/rule/99f3e6d7-b7bb-477d-ac28-92ee22726969`
|
||||
);
|
||||
|
||||
expect(response.status).to.eql(200);
|
||||
expect(response.body.actions).to.eql([
|
||||
{
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body.actions).toEqual([
|
||||
expect.objectContaining({
|
||||
id: '66a8ab7a-35cf-445e-ade3-215a029c6969',
|
||||
connector_type_id: '.servicenow',
|
||||
group: 'threshold met',
|
||||
|
@ -131,8 +131,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
comments: [{ commentId: '1', comment: 'sn comment' }],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: '66a8ab7a-35cf-445e-ade3-215a029c6969',
|
||||
connector_type_id: '.jira',
|
||||
group: 'threshold met',
|
||||
|
@ -155,8 +155,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: '66a8ab7a-35cf-445e-ade3-215a029c6969',
|
||||
connector_type_id: '.resilient',
|
||||
group: 'threshold met',
|
||||
|
@ -177,7 +177,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -190,8 +190,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.references).to.eql([
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.references).toEqual([
|
||||
{
|
||||
name: 'param:exceptionsList_0',
|
||||
id: 'endpoint_list',
|
||||
|
@ -219,10 +219,10 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(searchResult.statusCode).to.equal(200);
|
||||
expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).to.equal(1);
|
||||
expect(searchResult.statusCode).toEqual(200);
|
||||
expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).toEqual(1);
|
||||
const hit = searchResult.body.hits.hits[0];
|
||||
expect((hit!._source!.alert! as RawRule).legacyId).to.equal(
|
||||
expect((hit!._source!.alert! as RawRule).legacyId).toEqual(
|
||||
'74f3e6d7-b7bb-477d-ac28-92ee22728e6e'
|
||||
);
|
||||
});
|
||||
|
@ -241,31 +241,31 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(searchResult.statusCode).to.equal(200);
|
||||
expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).to.equal(1);
|
||||
expect(searchResult.statusCode).toEqual(200);
|
||||
expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).toEqual(1);
|
||||
const hit = searchResult.body.hits.hits[0];
|
||||
expect((hit!._source!.alert! as RawRule).actions! as RawRuleAction[]).to.eql([
|
||||
{
|
||||
expect((hit!._source!.alert! as RawRule).actions! as RawRuleAction[]).toEqual([
|
||||
expect.objectContaining({
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test.noop',
|
||||
group: 'default',
|
||||
params: {},
|
||||
},
|
||||
{
|
||||
}),
|
||||
expect.objectContaining({
|
||||
actionRef: 'preconfigured:my-slack1',
|
||||
actionTypeId: '.slack',
|
||||
group: 'default',
|
||||
params: {
|
||||
message: 'something happened!',
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
expect(hit!._source!.references!).to.eql([
|
||||
{
|
||||
expect(hit!._source!.references!).toEqual([
|
||||
expect.objectContaining({
|
||||
id: '66a8ab7a-35cf-445e-ade3-215a029c6969',
|
||||
name: 'action_0',
|
||||
type: 'action',
|
||||
},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -278,8 +278,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.references).to.eql([
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.references).toEqual([
|
||||
{
|
||||
name: 'param:alert_0',
|
||||
id: '1a4ed6ae-3c89-44b2-999d-db554144504c',
|
||||
|
@ -302,8 +302,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.alert?.params?.threatIndicatorPath).to.eql(
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.params?.threatIndicatorPath).toEqual(
|
||||
FILEBEAT_7X_INDICATOR_PATH
|
||||
);
|
||||
});
|
||||
|
@ -322,8 +322,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.alert?.params?.threatIndicatorPath).to.eql(
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.params?.threatIndicatorPath).toEqual(
|
||||
'custom.indicator.path'
|
||||
);
|
||||
});
|
||||
|
@ -342,8 +342,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.alert?.params?.threatIndicatorPath).not.to.eql(
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.params?.threatIndicatorPath).not.toEqual(
|
||||
FILEBEAT_7X_INDICATOR_PATH
|
||||
);
|
||||
});
|
||||
|
@ -356,8 +356,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.alert?.actions?.[0].group).to.be(
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.actions?.[0].group).toBe(
|
||||
'metrics.inventory_threshold.fired'
|
||||
);
|
||||
});
|
||||
|
@ -370,9 +370,9 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.alert?.alertTypeId).to.be('siem.queryRule');
|
||||
expect(response.body._source?.alert?.enabled).to.be(false);
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.alertTypeId).toBe('siem.queryRule');
|
||||
expect(response.body._source?.alert?.enabled).toBe(false);
|
||||
});
|
||||
|
||||
it('8.0.1 migrates and adds tags to disabled rules in 8.0', async () => {
|
||||
|
@ -383,7 +383,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(responseEnabledBeforeMigration.statusCode).to.eql(200);
|
||||
expect(responseEnabledBeforeMigration.statusCode).toEqual(200);
|
||||
const responseDisabledBeforeMigration = await es.get<{ alert: RawRule }>(
|
||||
{
|
||||
index: '.kibana',
|
||||
|
@ -391,17 +391,17 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(responseDisabledBeforeMigration.statusCode).to.eql(200);
|
||||
expect(responseDisabledBeforeMigration.statusCode).toEqual(200);
|
||||
|
||||
// Both should be disabled
|
||||
expect(responseEnabledBeforeMigration.body._source?.alert?.enabled).to.be(false);
|
||||
expect(responseDisabledBeforeMigration.body._source?.alert?.enabled).to.be(false);
|
||||
expect(responseEnabledBeforeMigration.body._source?.alert?.enabled).toBe(false);
|
||||
expect(responseDisabledBeforeMigration.body._source?.alert?.enabled).toBe(false);
|
||||
|
||||
// Only the rule that was enabled should be tagged
|
||||
expect(responseEnabledBeforeMigration.body._source?.alert?.tags).to.eql([
|
||||
expect(responseEnabledBeforeMigration.body._source?.alert?.tags).toEqual([
|
||||
'auto_disabled_8.0',
|
||||
]);
|
||||
expect(responseDisabledBeforeMigration.body._source?.alert?.tags).to.eql([]);
|
||||
expect(responseDisabledBeforeMigration.body._source?.alert?.tags).toEqual([]);
|
||||
});
|
||||
|
||||
it('8.2.0 migrates params to mapped_params for specific params properties', async () => {
|
||||
|
@ -413,8 +413,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
{ meta: true }
|
||||
);
|
||||
|
||||
expect(response.statusCode).to.equal(200);
|
||||
expect(response.body._source?.alert?.mapped_params).to.eql({
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.mapped_params).toEqual({
|
||||
risk_score: 90,
|
||||
severity: '80-critical',
|
||||
});
|
||||
|
@ -428,8 +428,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.equal(200);
|
||||
expect(response.body._source?.alert?.params.searchType).to.eql('esQuery');
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.params.searchType).toEqual('esQuery');
|
||||
});
|
||||
|
||||
it('8.3.0 removes internal tags in Security Solution rule', async () => {
|
||||
|
@ -441,8 +441,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
{ meta: true }
|
||||
);
|
||||
|
||||
expect(response.statusCode).to.equal(200);
|
||||
expect(response.body._source?.alert?.tags).to.eql(['test-tag-1', 'foo-tag']);
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.tags).toEqual(['test-tag-1', 'foo-tag']);
|
||||
});
|
||||
|
||||
it('8.4.1 removes IsSnoozedUntil', async () => {
|
||||
|
@ -460,9 +460,9 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
{ meta: true }
|
||||
);
|
||||
|
||||
expect(searchResult.statusCode).to.equal(200);
|
||||
expect(searchResult.statusCode).toEqual(200);
|
||||
const hit = searchResult.body.hits.hits[0];
|
||||
expect((hit!._source!.alert! as RawRule).isSnoozedUntil).to.be(undefined);
|
||||
expect((hit!._source!.alert! as RawRule).isSnoozedUntil).toBe(undefined);
|
||||
});
|
||||
|
||||
it('8.5.0 removes runtime and field params from older ES Query rules', async () => {
|
||||
|
@ -479,8 +479,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.alert?.params?.esQuery).to.eql(
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.params?.esQuery).toEqual(
|
||||
JSON.stringify({ query: { match_all: {} } }, null, 4)
|
||||
);
|
||||
});
|
||||
|
@ -499,8 +499,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.alert?.params?.esQuery).to.eql(
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.params?.esQuery).toEqual(
|
||||
'{\n\t"query":\n{\n\t"match_all":\n\t{}\n}\n}'
|
||||
);
|
||||
});
|
||||
|
@ -519,8 +519,8 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body._source?.alert?.params?.esQuery).to.eql('{"query":}');
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body._source?.alert?.params?.esQuery).toEqual('{"query":}');
|
||||
});
|
||||
|
||||
it('8.6.0 migrates executionStatus and monitoring', async () => {
|
||||
|
@ -533,7 +533,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
);
|
||||
const alert = response.body._source?.alert;
|
||||
|
||||
expect(alert?.monitoring).to.eql({
|
||||
expect(alert?.monitoring).toEqual({
|
||||
run: {
|
||||
history: [
|
||||
{
|
||||
|
@ -557,7 +557,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
});
|
||||
|
||||
expect(alert?.lastRun).to.eql({
|
||||
expect(alert?.lastRun).toEqual({
|
||||
outcome: 'succeeded',
|
||||
outcomeMsg: null,
|
||||
outcomeOrder: 0,
|
||||
|
@ -565,7 +565,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
alertsCount: {},
|
||||
});
|
||||
|
||||
expect(alert?.nextRun).to.eql(undefined);
|
||||
expect(alert?.nextRun).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('8.6 migrates executionStatus warnings and errors', async () => {
|
||||
|
@ -579,9 +579,9 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
|
||||
const alert = response.body._source?.alert;
|
||||
|
||||
expect(alert?.lastRun?.outcome).to.eql('warning');
|
||||
expect(alert?.lastRun?.warning).to.eql('warning reason');
|
||||
expect(alert?.lastRun?.outcomeMsg).to.eql('warning message');
|
||||
expect(alert?.lastRun?.outcome).toEqual('warning');
|
||||
expect(alert?.lastRun?.warning).toEqual('warning reason');
|
||||
expect(alert?.lastRun?.outcomeMsg).toEqual('warning message');
|
||||
});
|
||||
|
||||
it('8.7.0 adds aggType and groupBy to ES query rules', async () => {
|
||||
|
@ -604,10 +604,10 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
{ meta: true }
|
||||
);
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.statusCode).toEqual(200);
|
||||
response.body.hits.hits.forEach((hit) => {
|
||||
expect((hit?._source?.alert as RawRule)?.params?.aggType).to.eql('count');
|
||||
expect((hit?._source?.alert as RawRule)?.params?.groupBy).to.eql('all');
|
||||
expect((hit?._source?.alert as RawRule)?.params?.aggType).toEqual('count');
|
||||
expect((hit?._source?.alert as RawRule)?.params?.groupBy).toEqual('all');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -635,8 +635,39 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
|||
{ meta: true }
|
||||
);
|
||||
|
||||
expect(response.body._source?.alert?.params.logView).to.eql(logView);
|
||||
expect(response.body._source?.references).to.eql(references);
|
||||
expect(response.body._source?.alert?.params.logView).toEqual(logView);
|
||||
expect(response.body._source?.references).toEqual(references);
|
||||
});
|
||||
|
||||
it('8.7 adds uuid to the actions', async () => {
|
||||
const response = await es.get<{ alert: RawRule }>(
|
||||
{
|
||||
index: '.kibana',
|
||||
id: 'alert:9c003b00-00ee-11ec-b067-2524946ba327',
|
||||
},
|
||||
{ meta: true }
|
||||
);
|
||||
|
||||
const alert = response.body._source?.alert;
|
||||
|
||||
expect(alert?.actions).toEqual([
|
||||
{
|
||||
actionRef: 'action_0',
|
||||
actionTypeId: 'test.noop',
|
||||
group: 'default',
|
||||
params: {},
|
||||
uuid: expect.any(String),
|
||||
},
|
||||
{
|
||||
actionRef: 'preconfigured:my-slack1',
|
||||
actionTypeId: '.slack',
|
||||
group: 'default',
|
||||
params: {
|
||||
message: 'something happened!',
|
||||
},
|
||||
uuid: expect.any(String),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,7 +57,10 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const rule = await createRule(supertest, log, getRuleWithWebHookAction(hookAction.id));
|
||||
const bodyToCompare = removeServerGeneratedProperties(rule);
|
||||
expect(bodyToCompare).to.eql(
|
||||
getSimpleRuleOutputWithWebHookAction(`${bodyToCompare?.actions?.[0].id}`)
|
||||
getSimpleRuleOutputWithWebHookAction(
|
||||
`${bodyToCompare?.actions?.[0].id}`,
|
||||
`${bodyToCompare?.actions?.[0].uuid}`
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -165,7 +165,10 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
const outputRule1: ReturnType<typeof getSimpleRuleOutput> = {
|
||||
...getSimpleRuleOutput('rule-1'),
|
||||
actions: [action1, action2],
|
||||
actions: [
|
||||
{ ...action1, uuid: firstRule.actions[0].uuid },
|
||||
{ ...action2, uuid: firstRule.actions[1].uuid },
|
||||
],
|
||||
throttle: 'rule',
|
||||
};
|
||||
expect(firstRule).to.eql(outputRule1);
|
||||
|
@ -213,12 +216,12 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
const outputRule1: ReturnType<typeof getSimpleRuleOutput> = {
|
||||
...getSimpleRuleOutput('rule-2'),
|
||||
actions: [action],
|
||||
actions: [{ ...action, uuid: firstRule.actions[0].uuid }],
|
||||
throttle: 'rule',
|
||||
};
|
||||
const outputRule2: ReturnType<typeof getSimpleRuleOutput> = {
|
||||
...getSimpleRuleOutput('rule-1'),
|
||||
actions: [action],
|
||||
actions: [{ ...action, uuid: secondRule.actions[0].uuid }],
|
||||
throttle: 'rule',
|
||||
};
|
||||
expect(firstRule).to.eql(outputRule1);
|
||||
|
|
|
@ -126,7 +126,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
const ruleWithActions: ReturnType<typeof getSimpleRuleOutput> = {
|
||||
...getSimpleRuleOutput(),
|
||||
actions: [action],
|
||||
actions: [{ ...action, uuid: body.data[0].actions[0].uuid }],
|
||||
throttle: 'rule',
|
||||
};
|
||||
|
||||
|
@ -171,7 +171,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
const ruleWithActions: ReturnType<typeof getSimpleRuleOutput> = {
|
||||
...getSimpleRuleOutput(),
|
||||
actions: [action],
|
||||
actions: [{ ...action, uuid: body.data[0].actions[0].uuid }],
|
||||
throttle: '1h', // <-- throttle makes this a scheduled action
|
||||
};
|
||||
|
||||
|
|
|
@ -71,7 +71,10 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const bodyToCompare = removeServerGeneratedProperties(updatedRule);
|
||||
|
||||
const expected = {
|
||||
...getSimpleRuleOutputWithWebHookAction(`${bodyToCompare.actions?.[0].id}`),
|
||||
...getSimpleRuleOutputWithWebHookAction(
|
||||
`${bodyToCompare.actions?.[0].id}`,
|
||||
`${bodyToCompare.actions?.[0].uuid}`
|
||||
),
|
||||
version: 2, // version bump is required since this is an updated rule and this is part of the testing that we do bump the version number on update
|
||||
};
|
||||
expect(bodyToCompare).to.eql(expected);
|
||||
|
@ -147,7 +150,10 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const updatedRule = await updateRule(supertest, log, ruleToUpdate);
|
||||
const bodyToCompare = removeServerGeneratedProperties(updatedRule);
|
||||
|
||||
const expected = getSimpleRuleOutputWithWebHookAction(`${bodyToCompare.actions?.[0].id}`);
|
||||
const expected = getSimpleRuleOutputWithWebHookAction(
|
||||
`${bodyToCompare.actions?.[0].id}`,
|
||||
`${bodyToCompare.actions?.[0].uuid}`
|
||||
);
|
||||
|
||||
expect(bodyToCompare.actions).to.eql(expected.actions);
|
||||
expect(bodyToCompare.throttle).to.eql(expected.throttle);
|
||||
|
@ -180,7 +186,10 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
|
||||
expect(body.data.length).to.eql(1); // should have only one length to the data set, otherwise we have duplicates or the tags were removed and that is incredibly bad.
|
||||
const bodyToCompare = removeServerGeneratedProperties(body.data[0]);
|
||||
const expected = getSimpleRuleOutputWithWebHookAction(`${bodyToCompare.actions?.[0].id}`);
|
||||
const expected = getSimpleRuleOutputWithWebHookAction(
|
||||
`${bodyToCompare.actions?.[0].id}`,
|
||||
`${bodyToCompare.actions?.[0].uuid}`
|
||||
);
|
||||
|
||||
expect(bodyToCompare.actions).to.eql(expected.actions);
|
||||
expect(bodyToCompare.immutable).to.be(true);
|
||||
|
|
|
@ -121,6 +121,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
subject: 'Test Actions',
|
||||
to: ['test@test.com'],
|
||||
},
|
||||
uuid: ruleSO?.alert.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
expect(ruleSO?.alert.throttle).to.eql(null);
|
||||
|
@ -179,6 +180,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
},
|
||||
actionRef: 'action_0',
|
||||
group: 'default',
|
||||
uuid: ruleSO?.alert.actions[0].uuid,
|
||||
},
|
||||
{
|
||||
actionTypeId: '.slack',
|
||||
|
@ -187,6 +189,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
},
|
||||
actionRef: 'action_1',
|
||||
group: 'default',
|
||||
uuid: ruleSO?.alert.actions[1].uuid,
|
||||
},
|
||||
]);
|
||||
expect(ruleSO?.alert.throttle).to.eql('1h');
|
||||
|
@ -249,6 +252,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
subject: 'Test Actions',
|
||||
to: ['test@test.com'],
|
||||
},
|
||||
uuid: ruleSO?.alert.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
expect(ruleSO?.alert.throttle).to.eql('1d');
|
||||
|
@ -306,6 +310,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
subject: 'Test Actions',
|
||||
to: ['test@test.com'],
|
||||
},
|
||||
uuid: ruleSO?.alert.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
expect(ruleSO?.alert.throttle).to.eql('7d');
|
||||
|
|
|
@ -359,6 +359,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
.send({ id: rule.id, enabled: false })
|
||||
.expect(200);
|
||||
|
||||
const bodyToCompare = removeServerGeneratedProperties(patchResponse.body);
|
||||
const outputRule = getSimpleRuleOutput();
|
||||
outputRule.actions = [
|
||||
{
|
||||
|
@ -369,10 +370,11 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
message:
|
||||
'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
uuid: bodyToCompare.actions[0].uuid,
|
||||
},
|
||||
];
|
||||
outputRule.throttle = '1h';
|
||||
const bodyToCompare = removeServerGeneratedProperties(patchResponse.body);
|
||||
|
||||
expect(bodyToCompare).to.eql(outputRule);
|
||||
});
|
||||
|
||||
|
|
|
@ -181,6 +181,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
|
||||
// @ts-expect-error
|
||||
body.forEach((response) => {
|
||||
const bodyToCompare = removeServerGeneratedProperties(response);
|
||||
const outputRule = getSimpleRuleOutput(response.rule_id, false);
|
||||
outputRule.actions = [
|
||||
{
|
||||
|
@ -191,10 +192,10 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
message:
|
||||
'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
uuid: bodyToCompare.actions[0].uuid,
|
||||
},
|
||||
];
|
||||
outputRule.throttle = '1h';
|
||||
const bodyToCompare = removeServerGeneratedProperties(response);
|
||||
expect(bodyToCompare).to.eql(outputRule);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -173,6 +173,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
params: {
|
||||
body: '{"test":"a default action"}',
|
||||
},
|
||||
uuid: rule.actions[0].uuid,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -325,6 +326,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
params: {
|
||||
message: 'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
uuid: ruleBody.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -394,6 +396,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
params: {
|
||||
message: 'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
uuid: ruleBody.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -484,6 +487,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
message:
|
||||
'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
uuid: rule.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -1113,6 +1117,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
message:
|
||||
'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
uuid: setTagsRule.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -1396,6 +1401,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
...webHookActionMock,
|
||||
id: webHookConnector.id,
|
||||
action_type_id: '.webhook',
|
||||
uuid: body.attributes.results.updated[0].actions[0].uuid,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1452,6 +1458,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
...webHookActionMock,
|
||||
id: webHookConnector.id,
|
||||
action_type_id: '.webhook',
|
||||
uuid: body.attributes.results.updated[0].actions[0].uuid,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1544,6 +1551,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
...webHookActionMock,
|
||||
id: webHookConnector.id,
|
||||
action_type_id: '.webhook',
|
||||
uuid: body.attributes.results.updated[0].actions[0].uuid,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1598,11 +1606,12 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(200);
|
||||
|
||||
const expectedRuleActions = [
|
||||
defaultRuleAction,
|
||||
{ ...defaultRuleAction, uuid: body.attributes.results.updated[0].actions[0].uuid },
|
||||
{
|
||||
...webHookActionMock,
|
||||
id: webHookConnector.id,
|
||||
action_type_id: '.webhook',
|
||||
uuid: body.attributes.results.updated[0].actions[1].uuid,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1665,11 +1674,12 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(200);
|
||||
|
||||
const expectedRuleActions = [
|
||||
defaultRuleAction,
|
||||
{ ...defaultRuleAction, uuid: body.attributes.results.updated[0].actions[0].uuid },
|
||||
{
|
||||
...slackConnectorMockProps,
|
||||
id: slackConnector.id,
|
||||
action_type_id: '.slack',
|
||||
uuid: body.attributes.results.updated[0].actions[1].uuid,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1719,12 +1729,16 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
.expect(200);
|
||||
|
||||
// Check that the updated rule is returned with the response
|
||||
expect(body.attributes.results.updated[0].actions).to.eql([defaultRuleAction]);
|
||||
expect(body.attributes.results.updated[0].actions).to.eql([
|
||||
{ ...defaultRuleAction, uuid: createdRule.actions[0].uuid },
|
||||
]);
|
||||
|
||||
// Check that the updates have been persisted
|
||||
const { body: readRule } = await fetchRule(ruleId).expect(200);
|
||||
|
||||
expect(readRule.actions).to.eql([defaultRuleAction]);
|
||||
expect(readRule.actions).to.eql([
|
||||
{ ...defaultRuleAction, uuid: createdRule.actions[0].uuid },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should change throttle if actions list in payload is empty', async () => {
|
||||
|
@ -1816,6 +1830,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
...webHookActionMock,
|
||||
id: webHookConnector.id,
|
||||
action_type_id: '.webhook',
|
||||
uuid: editedRule.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
// version of prebuilt rule should not change
|
||||
|
@ -1829,6 +1844,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
...webHookActionMock,
|
||||
id: webHookConnector.id,
|
||||
action_type_id: '.webhook',
|
||||
uuid: readRule.actions[0].uuid,
|
||||
},
|
||||
]);
|
||||
expect(prebuiltRule.version).to.be(readRule.version);
|
||||
|
|
|
@ -135,7 +135,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const bodyToCompare = removeServerGeneratedProperties(body);
|
||||
const ruleWithActions: ReturnType<typeof getSimpleRuleOutput> = {
|
||||
...getSimpleRuleOutput(),
|
||||
actions: [action],
|
||||
actions: [{ ...action, uuid: bodyToCompare.actions[0].uuid }],
|
||||
throttle: 'rule',
|
||||
};
|
||||
expect(bodyToCompare).to.eql(ruleWithActions);
|
||||
|
@ -174,7 +174,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const bodyToCompare = removeServerGeneratedProperties(body);
|
||||
const ruleWithActions: ReturnType<typeof getSimpleRuleOutput> = {
|
||||
...getSimpleRuleOutput(),
|
||||
actions: [action],
|
||||
actions: [{ ...action, uuid: bodyToCompare.actions[0].uuid }],
|
||||
throttle: '1h', // <-- throttle makes this a scheduled action
|
||||
};
|
||||
expect(bodyToCompare).to.eql(ruleWithActions);
|
||||
|
|
|
@ -229,6 +229,8 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
.send(updatedRule)
|
||||
.expect(200);
|
||||
|
||||
const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body);
|
||||
|
||||
const outputRule = getSimpleRuleOutputWithoutRuleId();
|
||||
outputRule.name = 'some other name';
|
||||
outputRule.version = 2;
|
||||
|
@ -241,10 +243,11 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
message:
|
||||
'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
uuid: bodyToCompare.actions![0].uuid,
|
||||
},
|
||||
];
|
||||
outputRule.throttle = '1d';
|
||||
const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body);
|
||||
|
||||
expect(bodyToCompare).to.eql(outputRule);
|
||||
});
|
||||
|
||||
|
|
|
@ -166,6 +166,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
.expect(200);
|
||||
|
||||
body.forEach((response) => {
|
||||
const bodyToCompare = removeServerGeneratedProperties(response);
|
||||
const outputRule = getSimpleRuleOutput(response.rule_id);
|
||||
outputRule.name = 'some other name';
|
||||
outputRule.version = 2;
|
||||
|
@ -178,10 +179,11 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
message:
|
||||
'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
uuid: bodyToCompare.actions[0].uuid,
|
||||
},
|
||||
];
|
||||
outputRule.throttle = '1d';
|
||||
const bodyToCompare = removeServerGeneratedProperties(response);
|
||||
|
||||
expect(bodyToCompare).to.eql(outputRule);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,8 @@ import { getSimpleRuleOutput } from './get_simple_rule_output';
|
|||
import { RuleWithoutServerGeneratedProperties } from './remove_server_generated_properties';
|
||||
|
||||
export const getSimpleRuleOutputWithWebHookAction = (
|
||||
actionId: string
|
||||
actionId: string,
|
||||
uuid: string
|
||||
): RuleWithoutServerGeneratedProperties => ({
|
||||
...getSimpleRuleOutput(),
|
||||
throttle: 'rule',
|
||||
|
@ -21,6 +22,7 @@ export const getSimpleRuleOutputWithWebHookAction = (
|
|||
params: {
|
||||
body: '{}',
|
||||
},
|
||||
uuid,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -100,6 +100,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
message: MonitorStatusTranslations.defaultRecoveryMessage,
|
||||
},
|
||||
id: 'my-slack1',
|
||||
uuid: actions[0].uuid,
|
||||
},
|
||||
{
|
||||
actionTypeId: '.slack',
|
||||
|
@ -108,6 +109,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
message: MonitorStatusTranslations.defaultActionMessage,
|
||||
},
|
||||
id: 'my-slack1',
|
||||
uuid: actions[1].uuid,
|
||||
},
|
||||
]);
|
||||
expect(alertTypeId).to.eql('xpack.uptime.alerts.monitorStatus');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue