[ResponseOps][Rules] Version disable rule route (#188659)

## Summary

Parent Issue: #187572

Versions the `POST /rule/{id}/_disable` endpoint.

### Checklist
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
Antonio 2024-07-25 09:06:04 +02:00 committed by GitHub
parent 2c08b0f290
commit 425d6b10a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 213 additions and 102 deletions

View file

@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { disableRuleRequestBodySchema, disableRuleRequestParamsSchema } from './schemas/latest';
export {
disableRuleRequestBodySchema as disableRuleRequestBodySchemaV1,
disableRuleRequestParamsSchema as disableRuleRequestParamsSchemaV1,
} from './schemas/v1';
export type { DisableRuleRequestBody, DisableRuleRequestParams } from './types/latest';
export type {
DisableRuleRequestBody as DisableRuleRequestBodyV1,
DisableRuleRequestParams as DisableRuleRequestParamsV1,
} from './types/v1';

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export * from './v1';

View file

@ -0,0 +1,20 @@
/*
* 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 { schema } from '@kbn/config-schema';
export const disableRuleRequestBodySchema = schema.nullable(
schema.maybe(
schema.object({
untrack: schema.maybe(schema.boolean({ defaultValue: false })),
})
)
);
export const disableRuleRequestParamsSchema = schema.object({
id: schema.string(),
});

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export * from './v1';

View file

@ -0,0 +1,11 @@
/*
* 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 type { TypeOf } from '@kbn/config-schema';
import { disableRuleRequestBodySchemaV1, disableRuleRequestParamsSchemaV1 } from '..';
export type DisableRuleRequestBody = TypeOf<typeof disableRuleRequestBodySchemaV1>;
export type DisableRuleRequestParams = TypeOf<typeof disableRuleRequestParamsSchemaV1>;

View file

@ -6,7 +6,7 @@
*/
import { AlertConsumers } from '@kbn/rule-data-utils';
import { RulesClient, ConstructorOptions } from '../rules_client';
import { RulesClient, ConstructorOptions } from '../../../../rules_client/rules_client';
import {
savedObjectsClientMock,
loggingSystemMock,
@ -14,29 +14,29 @@ import {
uiSettingsServiceMock,
} from '@kbn/core/server/mocks';
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock';
import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock';
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks';
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
import { AlertingAuthorization } from '../../../../authorization/alerting_authorization';
import { ActionsAuthorization } from '@kbn/actions-plugin/server';
import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks';
import { getBeforeSetup, setGlobalDate } from './lib';
import { getBeforeSetup, setGlobalDate } from '../../../../rules_client/tests/lib';
import { eventLoggerMock } from '@kbn/event-log-plugin/server/event_logger.mock';
import { TaskStatus } from '@kbn/task-manager-plugin/server';
import { migrateLegacyActions } from '../lib';
import { migrateLegacyActionsMock } from '../lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock';
import { ConnectorAdapterRegistry } from '../../connector_adapters/connector_adapter_registry';
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
import { backfillClientMock } from '../../backfill_client/backfill_client.mock';
import { migrateLegacyActions } from '../../../../rules_client/lib';
import { migrateLegacyActionsMock } from '../../../../rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock';
import { ConnectorAdapterRegistry } from '../../../../connector_adapters/connector_adapter_registry';
import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects';
import { backfillClientMock } from '../../../../backfill_client/backfill_client.mock';
jest.mock('../lib/siem_legacy_actions/migrate_legacy_actions', () => {
jest.mock('../../../../rules_client/lib/siem_legacy_actions/migrate_legacy_actions', () => {
return {
migrateLegacyActions: jest.fn(),
};
});
jest.mock('../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation', () => ({
jest.mock('../../../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation', () => ({
bulkMarkApiKeysForInvalidation: jest.fn(),
}));
@ -107,7 +107,7 @@ beforeEach(() => {
setGlobalDate();
describe('disable()', () => {
describe('disableRule()', () => {
let rulesClient: RulesClient;
const existingRule = {
id: '1',
@ -158,7 +158,7 @@ describe('disable()', () => {
describe('authorization', () => {
test('ensures user is authorised to disable this type of rule under the consumer', async () => {
await rulesClient.disable({ id: '1' });
await rulesClient.disableRule({ id: '1' });
expect(authorization.ensureAuthorized).toHaveBeenCalledWith({
entity: 'rule',
@ -173,7 +173,7 @@ describe('disable()', () => {
new Error(`Unauthorized to disable a "myType" alert for "myApp"`)
);
await expect(rulesClient.disable({ id: '1' })).rejects.toMatchInlineSnapshot(
await expect(rulesClient.disableRule({ id: '1' })).rejects.toMatchInlineSnapshot(
`[Error: Unauthorized to disable a "myType" alert for "myApp"]`
);
@ -188,7 +188,7 @@ describe('disable()', () => {
describe('auditLogger', () => {
test('logs audit event when disabling a rule', async () => {
await rulesClient.disable({ id: '1' });
await rulesClient.disableRule({ id: '1' });
expect(auditLogger.log).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
@ -203,7 +203,7 @@ describe('disable()', () => {
test('logs audit event when not authorised to disable a rule', async () => {
authorization.ensureAuthorized.mockRejectedValue(new Error('Unauthorized'));
await expect(rulesClient.disable({ id: '1' })).rejects.toThrow();
await expect(rulesClient.disableRule({ id: '1' })).rejects.toThrow();
expect(auditLogger.log).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
@ -225,8 +225,8 @@ describe('disable()', () => {
});
});
test('disables an rule', async () => {
await rulesClient.disable({ id: '1' });
test('disables a rule', async () => {
await rulesClient.disableRule({ id: '1' });
expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled();
expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith(
RULE_SAVED_OBJECT_TYPE,
@ -304,7 +304,7 @@ describe('disable()', () => {
},
ownerId: null,
});
await rulesClient.disable({ id: '1', untrack: true });
await rulesClient.disableRule({ id: '1', untrack: true });
expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled();
expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith(
RULE_SAVED_OBJECT_TYPE,
@ -393,7 +393,7 @@ describe('disable()', () => {
test('disables the rule even if unable to retrieve task manager doc to generate untrack event log events', async () => {
taskManager.get.mockRejectedValueOnce(new Error('Fail'));
await rulesClient.disable({ id: '1', untrack: true });
await rulesClient.disableRule({ id: '1', untrack: true });
expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled();
expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith(
RULE_SAVED_OBJECT_TYPE,
@ -441,12 +441,12 @@ describe('disable()', () => {
expect(eventLogger.logEvent).toHaveBeenCalledTimes(0);
expect(rulesClientParams.logger.warn).toHaveBeenCalledWith(
`rulesClient.disable('1') - Could not write untrack events - Fail`
`rulesClient.disableRule('1') - Could not write untrack events - Fail`
);
});
test('should not untrack rule alert if untrack is false', async () => {
await rulesClient.disable({ id: '1', untrack: false });
await rulesClient.disableRule({ id: '1', untrack: false });
expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled();
expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith(
RULE_SAVED_OBJECT_TYPE,
@ -496,7 +496,7 @@ describe('disable()', () => {
test('falls back when getDecryptedAsInternalUser throws an error', async () => {
encryptedSavedObjects.getDecryptedAsInternalUser.mockRejectedValueOnce(new Error('Fail'));
await rulesClient.disable({ id: '1' });
await rulesClient.disableRule({ id: '1' });
expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith(RULE_SAVED_OBJECT_TYPE, '1');
expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith(
RULE_SAVED_OBJECT_TYPE,
@ -548,7 +548,7 @@ describe('disable()', () => {
},
});
await rulesClient.disable({ id: '1' });
await rulesClient.disableRule({ id: '1' });
expect(unsecuredSavedObjectsClient.update).not.toHaveBeenCalled();
expect(taskManager.bulkDisable).not.toHaveBeenCalled();
expect(taskManager.removeIfExists).not.toHaveBeenCalledWith();
@ -557,7 +557,7 @@ describe('disable()', () => {
test('swallows error when failing to load decrypted saved object', async () => {
encryptedSavedObjects.getDecryptedAsInternalUser.mockRejectedValueOnce(new Error('Fail'));
await rulesClient.disable({ id: '1' });
await rulesClient.disableRule({ id: '1' });
expect(unsecuredSavedObjectsClient.update).toHaveBeenCalled();
expect(taskManager.bulkDisable).toHaveBeenCalled();
expect(taskManager.removeIfExists).not.toHaveBeenCalledWith();
@ -569,7 +569,7 @@ describe('disable()', () => {
test('throws when unsecuredSavedObjectsClient update fails', async () => {
unsecuredSavedObjectsClient.update.mockRejectedValueOnce(new Error('Failed to update'));
await expect(rulesClient.disable({ id: '1' })).rejects.toThrowErrorMatchingInlineSnapshot(
await expect(rulesClient.disableRule({ id: '1' })).rejects.toThrowErrorMatchingInlineSnapshot(
`"Failed to update"`
);
expect(taskManager.bulkDisable).not.toHaveBeenCalled();
@ -579,12 +579,32 @@ describe('disable()', () => {
test('throws when failing to disable task', async () => {
taskManager.bulkDisable.mockRejectedValueOnce(new Error('Failed to disable task'));
await expect(rulesClient.disable({ id: '1' })).rejects.toThrowErrorMatchingInlineSnapshot(
await expect(rulesClient.disableRule({ id: '1' })).rejects.toThrowErrorMatchingInlineSnapshot(
`"Failed to disable task"`
);
expect(taskManager.removeIfExists).not.toHaveBeenCalledWith();
});
test('throws if id param does not match the schema', async () => {
await expect(
// @ts-ignore: this is what we are testing
rulesClient.disableRule({ id: 1 })
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Error validating disable rule parameters - [id]: expected value of type [string] but got [number]"`
);
expect(taskManager.removeIfExists).not.toHaveBeenCalledWith();
});
test('throws if untrack param does not match the schema', async () => {
await expect(
// @ts-ignore: this is what we are testing
rulesClient.disableRule({ id: '1', untrack: 'foo' })
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Error validating disable rule parameters - [untrack]: expected value of type [boolean] but got [string]"`
);
expect(taskManager.removeIfExists).not.toHaveBeenCalledWith();
});
test('removes task document if scheduled task id does not match rule id', async () => {
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValue({
...existingRule,
@ -593,7 +613,7 @@ describe('disable()', () => {
scheduledTaskId: 'task-123',
},
});
await rulesClient.disable({ id: '1' });
await rulesClient.disableRule({ id: '1' });
expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled();
expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith(
RULE_SAVED_OBJECT_TYPE,
@ -644,7 +664,7 @@ describe('disable()', () => {
},
});
taskManager.removeIfExists.mockRejectedValueOnce(new Error('Failed to remove task'));
await expect(rulesClient.disable({ id: '1' })).rejects.toThrowErrorMatchingInlineSnapshot(
await expect(rulesClient.disableRule({ id: '1' })).rejects.toThrowErrorMatchingInlineSnapshot(
`"Failed to remove task"`
);
expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled();
@ -697,7 +717,7 @@ describe('disable()', () => {
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValue(existingDecryptedSiemRule);
(migrateLegacyActions as jest.Mock).mockResolvedValue(migrateLegacyActionsMock);
await rulesClient.disable({ id: '1' });
await rulesClient.disableRule({ id: '1' });
expect(migrateLegacyActions).toHaveBeenCalledWith(expect.any(Object), {
attributes: expect.objectContaining({ consumer: AlertConsumers.SIEM }),

View file

@ -6,46 +6,43 @@
*/
import type { SavedObjectReference } from '@kbn/core/server';
import { RawRule } from '../../types';
import { WriteOperations, AlertingAuthorizationEntity } from '../../authorization';
import { retryIfConflicts } from '../../lib/retry_if_conflicts';
import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events';
import { RulesClientContext } from '../types';
import { untrackRuleAlerts, updateMeta, migrateLegacyActions } from '../lib';
import { RuleAttributes } from '../../data/rule/types';
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
import Boom from '@hapi/boom';
import { RawRule } from '../../../../types';
import { WriteOperations, AlertingAuthorizationEntity } from '../../../../authorization';
import { retryIfConflicts } from '../../../../lib/retry_if_conflicts';
import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events';
import { RulesClientContext } from '../../../../rules_client/types';
import { untrackRuleAlerts, updateMeta, migrateLegacyActions } from '../../../../rules_client/lib';
import { RuleAttributes } from '../../../../data/rule/types';
import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects';
import { DisableRuleParams } from './types';
import { disableRuleParamsSchema } from './schemas';
export async function disable(
export async function disableRule(
context: RulesClientContext,
{
id,
untrack = false,
}: {
id: string;
untrack?: boolean;
}
{ id, untrack = false }: DisableRuleParams
): Promise<void> {
return await retryIfConflicts(
context.logger,
`rulesClient.disable('${id}')`,
`rulesClient.disableRule('${id}')`,
async () => await disableWithOCC(context, { id, untrack })
);
}
async function disableWithOCC(
context: RulesClientContext,
{
id,
untrack = false,
}: {
id: string;
untrack?: boolean;
}
{ id, untrack = false }: DisableRuleParams
) {
let attributes: RawRule;
let version: string | undefined;
let references: SavedObjectReference[];
try {
disableRuleParamsSchema.validate({ id, untrack });
} catch (error) {
throw Boom.badRequest(`Error validating disable rule parameters - ${error.message}`);
}
try {
const decryptedAlert =
await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawRule>(

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export { disableRule } from './disable_rule';
export type { DisableRuleParams } from './types';

View file

@ -0,0 +1,13 @@
/*
* 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 { schema } from '@kbn/config-schema';
export const disableRuleParamsSchema = schema.object({
id: schema.string(),
untrack: schema.maybe(schema.boolean({ defaultValue: false })),
});

View file

@ -0,0 +1,10 @@
/*
* 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 type { TypeOf } from '@kbn/config-schema';
import { disableRuleParamsSchema } from '../schemas';
export type DisableRuleParams = TypeOf<typeof disableRuleParamsSchema>;

View file

@ -18,7 +18,7 @@ import { getRuleRoute, getInternalRuleRoute } from './rule/apis/get/get_rule_rou
import { updateRuleRoute } from './rule/apis/update/update_rule_route';
import { deleteRuleRoute } from './rule/apis/delete/delete_rule_route';
import { aggregateRulesRoute } from './rule/apis/aggregate/aggregate_rules_route';
import { disableRuleRoute } from './disable_rule';
import { disableRuleRoute } from './rule/apis/disable/disable_rule_route';
import { enableRuleRoute } from './rule/apis/enable/enable_rule';
import { findRulesRoute, findInternalRulesRoute } from './rule/apis/find/find_rules_route';
import { getRuleAlertSummaryRoute } from './get_rule_alert_summary';

View file

@ -38,7 +38,7 @@ describe('disableAlertRoute', () => {
expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}/_disable"`);
rulesClient.disable.mockResolvedValueOnce();
rulesClient.disableRule.mockResolvedValueOnce();
const [context, req, res] = mockHandlerArguments(
{ rulesClient },
@ -52,8 +52,8 @@ describe('disableAlertRoute', () => {
expect(await handler(context, req, res)).toEqual(undefined);
expect(rulesClient.disable).toHaveBeenCalledTimes(1);
expect(rulesClient.disable.mock.calls[0]).toMatchInlineSnapshot(`
expect(rulesClient.disableRule).toHaveBeenCalledTimes(1);
expect(rulesClient.disableRule.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"id": "1",
@ -72,7 +72,7 @@ describe('disableAlertRoute', () => {
const [, handler] = router.post.mock.calls[0];
rulesClient.disable.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid'));
rulesClient.disableRule.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid'));
const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [
'ok',

View file

@ -39,7 +39,7 @@ export const disableAlertRoute = (
const rulesClient = (await context.alerting).getRulesClient();
const { id } = req.params;
try {
await rulesClient.disable({ id });
await rulesClient.disableRule({ id });
return res.noContent();
} catch (e) {
if (e instanceof RuleTypeDisabledError) {

View file

@ -5,16 +5,16 @@
* 2.0.
*/
import { disableRuleRoute } from './disable_rule';
import { disableRuleRoute } from './disable_rule_route';
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { rulesClientMock } from '../rules_client.mock';
import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled';
import { licenseStateMock } from '../../../../lib/license_state.mock';
import { mockHandlerArguments } from '../../../_mock_handler_arguments';
import { rulesClientMock } from '../../../../rules_client.mock';
import { RuleTypeDisabledError } from '../../../../lib/errors/rule_type_disabled';
const rulesClient = rulesClientMock.create();
jest.mock('../lib/license_api_access', () => ({
jest.mock('../../../../lib/license_api_access', () => ({
verifyApiAccess: jest.fn(),
}));
@ -33,7 +33,7 @@ describe('disableRuleRoute', () => {
expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id}/_disable"`);
rulesClient.disable.mockResolvedValueOnce();
rulesClient.disableRule.mockResolvedValueOnce();
const [context, req, res] = mockHandlerArguments(
{ rulesClient },
@ -47,8 +47,8 @@ describe('disableRuleRoute', () => {
expect(await handler(context, req, res)).toEqual(undefined);
expect(rulesClient.disable).toHaveBeenCalledTimes(1);
expect(rulesClient.disable.mock.calls[0]).toMatchInlineSnapshot(`
expect(rulesClient.disableRule).toHaveBeenCalledTimes(1);
expect(rulesClient.disableRule.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"id": "1",
@ -68,7 +68,7 @@ describe('disableRuleRoute', () => {
const [, handler] = router.post.mock.calls[0];
rulesClient.disable.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid'));
rulesClient.disableRule.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid'));
const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [
'ok',

View file

@ -6,22 +6,15 @@
*/
import { IRouter } from '@kbn/core/server';
import { schema } from '@kbn/config-schema';
import { ILicenseState, RuleTypeDisabledError } from '../lib';
import { verifyAccessAndContext } from './lib';
import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types';
const paramSchema = schema.object({
id: schema.string(),
});
const bodySchema = schema.nullable(
schema.maybe(
schema.object({
untrack: schema.maybe(schema.boolean({ defaultValue: false })),
})
)
);
import {
disableRuleRequestParamsSchemaV1,
disableRuleRequestBodySchemaV1,
DisableRuleRequestParamsV1,
DisableRuleRequestBodyV1,
} from '../../../../../common/routes/rule/apis/disable';
import { ILicenseState, RuleTypeDisabledError } from '../../../../lib';
import { verifyAccessAndContext } from '../../../lib';
import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../../../../types';
export const disableRuleRoute = (
router: IRouter<AlertingRequestHandlerContext>,
@ -32,20 +25,24 @@ export const disableRuleRoute = (
path: `${BASE_ALERTING_API_PATH}/rule/{id}/_disable`,
options: {
access: 'public',
summary: `Disable a rule`,
summary: 'Disable a rule',
},
validate: {
params: paramSchema,
body: bodySchema,
params: disableRuleRequestParamsSchemaV1,
body: disableRuleRequestBodySchemaV1,
},
},
router.handleLegacyErrors(
verifyAccessAndContext(licenseState, async function (context, req, res) {
const rulesClient = (await context.alerting).getRulesClient();
const { id } = req.params;
const { untrack = false } = req.body || {};
const { id }: DisableRuleRequestParamsV1 = req.params;
const body: DisableRuleRequestBodyV1 = req.body || {};
const { untrack = false } = body;
const disableParams = { id, untrack };
try {
await rulesClient.disable({ id, untrack });
await rulesClient.disableRule(disableParams);
return res.noContent();
} catch (e) {
if (e instanceof RuleTypeDisabledError) {

View file

@ -21,8 +21,8 @@ const createRulesClientMock = () => {
find: jest.fn(),
delete: jest.fn(),
update: jest.fn(),
disableRule: jest.fn(),
enableRule: jest.fn(),
disable: jest.fn(),
updateRuleApiKey: jest.fn(),
muteAll: jest.fn(),
unmuteAll: jest.fn(),

View file

@ -89,7 +89,7 @@ export const untrackRuleAlerts = async (
} catch (error) {
// this should not block the rest of the disable process
context.logger.warn(
`rulesClient.disable('${id}') - Could not write untrack events - ${error.message}`
`rulesClient.disableRule('${id}') - Could not write untrack events - ${error.message}`
);
}
});

View file

@ -55,7 +55,7 @@ import {
import { bulkEnableRules, BulkEnableRulesParams } from '../application/rule/methods/bulk_enable';
import { enableRule } from '../application/rule/methods/enable_rule/enable_rule';
import { updateRuleApiKey } from '../application/rule/methods/update_api_key/update_rule_api_key';
import { disable } from './methods/disable';
import { disableRule } from '../application/rule/methods/disable/disable_rule';
import { clearExpiredSnoozes } from './methods/clear_expired_snoozes';
import { muteInstance } from '../application/rule/methods/mute_alert/mute_instance';
import { muteAll } from './methods/mute_all';
@ -75,6 +75,7 @@ import { getBackfill } from '../application/backfill/methods/get';
import { findBackfill } from '../application/backfill/methods/find';
import { deleteBackfill } from '../application/backfill/methods/delete';
import { FindBackfillParams } from '../application/backfill/methods/find/types';
import { DisableRuleParams } from '../application/rule/methods/disable';
import { EnableRuleParams } from '../application/rule/methods/enable_rule';
export type ConstructorOptions = Omit<
@ -166,9 +167,8 @@ export class RulesClient {
bulkDisableRules(this.context, options);
public updateRuleApiKey = (params: { id: string }) => updateRuleApiKey(this.context, params);
public disableRule = (params: DisableRuleParams) => disableRule(this.context, params);
public enableRule = (params: EnableRuleParams) => enableRule(this.context, params);
public disable = (options: { id: string; untrack?: boolean }) => disable(this.context, options);
public snooze = (options: SnoozeRuleOptions) => snoozeRule(this.context, options);
public unsnooze = (options: UnsnoozeParams) => unsnoozeRule(this.context, options);

View file

@ -173,7 +173,7 @@ async function enable(success: boolean) {
async function disable(success: boolean) {
try {
await rulesClient.disable({ id: MockRuleId });
await rulesClient.disableRule({ id: MockRuleId });
} catch (err) {
return expectConflict(success, err);
}

View file

@ -107,7 +107,7 @@ describe('DetectionRulesClient.patchRule', () => {
const rule = await detectionRulesClient.patchRule({ rulePatch });
expect(rule.enabled).toBe(false);
expect(rulesClient.disable).toHaveBeenCalledWith(
expect(rulesClient.disableRule).toHaveBeenCalledWith(
expect.objectContaining({
id: existingRule.id,
})

View file

@ -111,7 +111,7 @@ describe('DetectionRulesClient.updateRule', () => {
await detectionRulesClient.updateRule({ ruleUpdate });
expect(rulesClient.disable).toHaveBeenCalledWith(
expect(rulesClient.disableRule).toHaveBeenCalledWith(
expect.objectContaining({
id: existingRule.id,
})

View file

@ -22,7 +22,7 @@ export const toggleRuleEnabledOnUpdate = async (
updatedRule: RuleResponse
): Promise<{ enabled: boolean }> => {
if (existingRule.enabled && !updatedRule.enabled) {
await rulesClient.disable({ id: existingRule.id });
await rulesClient.disableRule({ id: existingRule.id });
return { enabled: false };
}