[Security Solution] Remove references to ruleRegistryEnabled feature flag (#128913)

* Remove references to ruleRegistryEnabled feature flag

* Fix remaining tests using describe.each

* Test fixes

* alert -> rule

* Fix import rule tests

* Fix output_index in tests

* Tryin' again

* Another test fix

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Madison Caldwell 2022-04-25 16:08:24 -04:00 committed by GitHub
parent 80a2aa1f74
commit 414ad78ffa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
86 changed files with 935 additions and 1490 deletions

View file

@ -12,7 +12,6 @@ export type ExperimentalFeatures = typeof allowedExperimentalValues;
* This object is then used to validate and parse the value entered.
*/
export const allowedExperimentalValues = Object.freeze({
ruleRegistryEnabled: true,
tGridEnabled: true,
tGridEventRenderedViewEnabled: true,
excludePoliciesInFilterEnabled: false,

View file

@ -43,11 +43,6 @@ export const AlertsCountPanel = memo<AlertsCountPanelProps>(
const uniqueQueryId = useMemo(() => `${DETECTIONS_ALERTS_COUNT_ID}-${uuid.v4()}`, []);
const [selectedStackByOption, setSelectedStackByOption] = useState(DEFAULT_STACK_BY_FIELD);
// TODO: Once we are past experimental phase this code should be removed
// const fetchMethod = useIsExperimentalFeatureEnabled('ruleRegistryEnabled')
// ? fetchQueryRuleRegistryAlerts
// : fetchQueryAlerts;
// Disabling the fecth method in useQueryAlerts since it is defaulted to the old one
// const fetchMethod = fetchQueryRuleRegistryAlerts;

View file

@ -9,7 +9,6 @@ import { useEffect, useState } from 'react';
import { isSecurityAppError } from '@kbn/securitysolution-t-grid';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
import { createSignalIndex, getSignalIndex } from './api';
import * as i18n from './translations';
import { useAlertsPrivileges } from './use_alerts_privileges';
@ -39,8 +38,6 @@ export const useSignalIndex = (): ReturnSignalIndex => {
});
const { addError } = useAppToasts();
const { hasIndexRead } = useAlertsPrivileges();
// TODO: Once we are past experimental phase this code should be removed
const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled');
useEffect(() => {
let isSubscribed = true;
@ -118,7 +115,7 @@ export const useSignalIndex = (): ReturnSignalIndex => {
isSubscribed = false;
abortCtrl.abort();
};
}, [addError, hasIndexRead, ruleRegistryEnabled]);
}, [addError, hasIndexRead]);
return { loading, ...signalIndex };
};

View file

@ -15,7 +15,6 @@ import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBo
import { DataView, isCompleteResponse, isErrorResponse } from '@kbn/data-plugin/common';
import { ESQuery } from '../../../common/typed_json';
import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features';
import { inputsModel } from '../../common/store';
import { useKibana } from '../../common/lib/kibana';
import { createFilter } from '../../common/containers/helpers';
@ -211,9 +210,6 @@ export const useTimelineEvents = ({
});
const { addWarning } = useAppToasts();
// TODO: Once we are past experimental phase this code should be removed
const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled');
const timelineSearch = useCallback(
(request: TimelineRequest<typeof language> | null) => {
if (request == null || pageName === '' || skip) {
@ -332,10 +328,7 @@ export const useTimelineEvents = ({
);
useEffect(() => {
if (
skipQueryForDetectionsPage(id, indexNames, ruleRegistryEnabled) ||
indexNames.length === 0
) {
if (skipQueryForDetectionsPage(id, indexNames) || indexNames.length === 0) {
return;
}
@ -397,10 +390,7 @@ export const useTimelineEvents = ({
activeTimeline.setActivePage(newActivePage);
}
}
if (
!skipQueryForDetectionsPage(id, indexNames, ruleRegistryEnabled) &&
!deepEqual(prevRequest, currentRequest)
) {
if (!skipQueryForDetectionsPage(id, indexNames) && !deepEqual(prevRequest, currentRequest)) {
return currentRequest;
}
return prevRequest;
@ -416,7 +406,6 @@ export const useTimelineEvents = ({
id,
language,
limit,
ruleRegistryEnabled,
startDate,
sort,
fields,

View file

@ -44,12 +44,7 @@ const withExperimentalFeature = (
};
};
const withRuleRegistryEnabled = (config: ConfigType, isEnabled: boolean): ConfigType => {
return isEnabled ? withExperimentalFeature(config, 'ruleRegistryEnabled') : config;
};
export const configMock = {
createDefault: createMockConfig,
withExperimentalFeature,
withRuleRegistryEnabled,
};

View file

@ -6,11 +6,12 @@
*/
import { loggingSystemMock } from '@kbn/core/server/mocks';
import { getAlertMock } from '../routes/__mocks__/request_responses';
import { alertsMock, RuleExecutorServicesMock } from '@kbn/alerting-plugin/server/mocks';
import { getRuleMock } from '../routes/__mocks__/request_responses';
// eslint-disable-next-line no-restricted-imports
import { legacyRulesNotificationAlertType } from './legacy_rules_notification_alert_type';
import { buildSignalsSearchQuery } from './build_signals_query';
import { alertsMock, RuleExecutorServicesMock } from '@kbn/alerting-plugin/server/mocks';
// eslint-disable-next-line no-restricted-imports
import { LegacyNotificationExecutorOptions } from './legacy_types';
import {
@ -75,10 +76,7 @@ describe('legacyRules_notification_alert_type', () => {
});
});
describe.each([
['Legacy', false],
['RAC', true],
])('executor - %s', (_, isRuleRegistryEnabled) => {
describe('executor', () => {
it('throws an error if rule alert was not found', async () => {
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
@ -93,7 +91,7 @@ describe('legacyRules_notification_alert_type', () => {
});
it('should call buildSignalsSearchQuery with proper params', async () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
@ -118,7 +116,7 @@ describe('legacyRules_notification_alert_type', () => {
});
it('should resolve results_link when meta is undefined to use "/app/security"', async () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
delete ruleAlert.params.meta;
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'rule-id',
@ -144,7 +142,7 @@ describe('legacyRules_notification_alert_type', () => {
});
it('should resolve results_link when meta is an empty object to use "/app/security"', async () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
ruleAlert.params.meta = {};
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'rule-id',
@ -169,7 +167,7 @@ describe('legacyRules_notification_alert_type', () => {
});
it('should resolve results_link to custom kibana link when given one', async () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
ruleAlert.params.meta = {
kibana_siem_app_url: 'http://localhost',
};
@ -196,7 +194,7 @@ describe('legacyRules_notification_alert_type', () => {
});
it('should not call alertFactory.create if signalsCount was 0', async () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',
@ -213,7 +211,7 @@ describe('legacyRules_notification_alert_type', () => {
});
it('should call scheduleActions if signalsCount was greater than 0', async () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
type: 'type',

View file

@ -206,18 +206,18 @@ export const getEmptyFindResult = (): FindHit => ({
data: [],
});
export const getFindResultWithSingleHit = (isRuleRegistryEnabled: boolean): FindHit => ({
export const getFindResultWithSingleHit = (): FindHit => ({
page: 1,
perPage: 1,
total: 1,
data: [getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())],
data: [getRuleMock(getQueryRuleParams())],
});
export const nonRuleFindResult = (isRuleRegistryEnabled: boolean): FindHit => ({
export const nonRuleFindResult = (): FindHit => ({
page: 1,
perPage: 1,
total: 1,
data: [nonRuleAlert(isRuleRegistryEnabled)],
data: [nonRuleAlert()],
});
export const getFindResultWithMultiHits = ({
@ -381,22 +381,19 @@ export const createActionResult = (): ActionResult => ({
isPreconfigured: false,
});
export const nonRuleAlert = (isRuleRegistryEnabled: boolean) => ({
export const nonRuleAlert = () => ({
// Defaulting to QueryRuleParams because ts doesn't like empty objects
...getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
...getRuleMock(getQueryRuleParams()),
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bc',
name: 'Non-Rule Alert',
alertTypeId: 'something',
});
export const getAlertMock = <T extends RuleParams>(
isRuleRegistryEnabled: boolean,
params: T
): SanitizedRule<T> => ({
export const getRuleMock = <T extends RuleParams>(params: T): SanitizedRule<T> => ({
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
name: 'Detect Root/Admin Users',
tags: [`${INTERNAL_RULE_ID_KEY}:rule-1`, `${INTERNAL_IMMUTABLE_KEY}:false`],
alertTypeId: isRuleRegistryEnabled ? ruleTypeMappings[params.type] : 'siem.signals',
alertTypeId: ruleTypeMappings[params.type],
consumer: 'siem',
params,
createdAt: new Date('2019-12-13T16:40:33.400Z'),
@ -418,12 +415,9 @@ export const getAlertMock = <T extends RuleParams>(
},
});
export const resolveAlertMock = <T extends RuleParams>(
isRuleRegistryEnabled: boolean,
params: T
): ResolvedSanitizedRule<T> => ({
export const resolveRuleMock = <T extends RuleParams>(params: T): ResolvedSanitizedRule<T> => ({
outcome: 'exactMatch',
...getAlertMock(isRuleRegistryEnabled, params),
...getRuleMock(params),
});
export const updateActionResult = (): ActionResult => ({

View file

@ -68,7 +68,6 @@ export const createIndexRoute = (router: SecuritySolutionPluginRouter) => {
export const createDetectionIndex = async (
context: SecuritySolutionApiRequestHandlerContext
): Promise<void> => {
const config = context.getConfig();
const esClient = context.core.elasticsearch.client.asCurrentUser;
const siemClient = context.getAppClient();
const spaceId = context.getSpaceId();
@ -78,11 +77,10 @@ export const createDetectionIndex = async (
context.core.elasticsearch.client.asInternalUser,
index
);
const { ruleRegistryEnabled } = config.experimentalFeatures;
// If using the rule registry implementation, we don't want to create new .siem-signals indices -
// only create/update resources if there are existing indices
if (ruleRegistryEnabled && !indexExists) {
// We don't want to create new .siem-signals indices - only create/update
// resources if there are existing indices
if (!indexExists) {
return;
}

View file

@ -9,10 +9,10 @@ import {
getEmptyFindResult,
addPrepackagedRulesRequest,
getFindResultWithSingleHit,
getAlertMock,
getRuleMock,
getBasicEmptySearchResponse,
} from '../__mocks__/request_responses';
import { configMock, requestContextMock, serverMock } from '../__mocks__';
import { requestContextMock, serverMock } from '../__mocks__';
import { AddPrepackagedRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema';
import { addPrepackedRulesRoute, createPrepackagedRules } from './add_prepackaged_rules_route';
import { listMock } from '@kbn/lists-plugin/server/mocks';
@ -74,19 +74,14 @@ describe('add_prepackaged_rules_route', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let mockExceptionsClient: ExceptionListClient;
const defaultConfig = context.securitySolution.getConfig();
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());
mockExceptionsClient = listMock.getExceptionListClient();
context.securitySolution.getConfig.mockImplementation(() =>
configMock.withRuleRegistryEnabled(defaultConfig, true)
);
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(true));
clients.rulesClient.update.mockResolvedValue(getAlertMock(true, getQueryRuleParams()));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
clients.rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams()));
(installPrepackagedTimelines as jest.Mock).mockReset();
(installPrepackagedTimelines as jest.Mock).mockResolvedValue({

View file

@ -6,7 +6,7 @@
*/
import moment from 'moment';
import { transformError, getIndexExists } from '@kbn/securitysolution-es-utils';
import { transformError } from '@kbn/securitysolution-es-utils';
import { validate } from '@kbn/securitysolution-io-ts-utils';
import { RulesClient } from '@kbn/alerting-plugin/server';
import { ExceptionListClient } from '@kbn/lists-plugin/server';
@ -88,7 +88,6 @@ export const createPrepackagedRules = async (
): Promise<PrePackagedRulesAndTimelinesSchema | null> => {
const config = context.getConfig();
const frameworkRequest = context.getFrameworkRequest();
const esClient = context.core.elasticsearch.client;
const savedObjectsClient = context.core.savedObjects.client;
const siemClient = context.getAppClient();
const exceptionsListClient = context.getExceptionListClient() ?? exceptionsClient;
@ -98,7 +97,6 @@ export const createPrepackagedRules = async (
maxTimelineImportExportSize,
prebuiltRulesFromFileSystem,
prebuiltRulesFromSavedObjects,
experimentalFeatures: { ruleRegistryEnabled },
} = config;
if (!siemClient || !rulesClient) {
@ -117,24 +115,12 @@ export const createPrepackagedRules = async (
);
const prepackagedRules = await getExistingPrepackagedRules({
rulesClient,
isRuleRegistryEnabled: ruleRegistryEnabled,
});
const rulesToInstall = getRulesToInstall(latestPrepackagedRules, prepackagedRules);
const rulesToUpdate = getRulesToUpdate(latestPrepackagedRules, prepackagedRules);
const signalsIndex = siemClient.getSignalsIndex();
if (!ruleRegistryEnabled && (rulesToInstall.length !== 0 || rulesToUpdate.length !== 0)) {
const signalsIndexExists = await getIndexExists(esClient.asCurrentUser, signalsIndex);
if (!signalsIndexExists) {
throw new PrepackagedRulesError(
`Pre-packaged rules cannot be installed until the signals index is created: ${signalsIndex}`,
400
);
}
}
await Promise.all(
installPrepackagedRules(rulesClient, rulesToInstall, signalsIndex, ruleRegistryEnabled)
);
await Promise.all(installPrepackagedRules(rulesClient, rulesToInstall, signalsIndex));
const timeline = await installPrepackagedTimelines(
maxTimelineImportExportSize,
frameworkRequest,
@ -149,7 +135,6 @@ export const createPrepackagedRules = async (
savedObjectsClient,
rulesToUpdate,
signalsIndex,
ruleRegistryEnabled,
context.getRuleExecutionLog()
);

View file

@ -12,7 +12,7 @@ import {
getReadBulkRequest,
getFindResultWithSingleHit,
getEmptyFindResult,
getAlertMock,
getRuleMock,
createBulkMlRuleRequest,
getBasicEmptySearchResponse,
getBasicNoShardsSearchResponse,
@ -27,10 +27,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
describe.each([
['Legacy', false],
['RAC', true],
])('create_rules_bulk - %s', (_, isRuleRegistryEnabled) => {
describe('create_rules_bulk', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.createSetupContract>;
@ -42,14 +39,12 @@ describe.each([
const logger = loggingSystemMock.createLogger();
clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); // no existing rules
clients.rulesClient.create.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
); // successful creation
clients.rulesClient.create.mockResolvedValue(getRuleMock(getQueryRuleParams())); // successful creation
context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue(
elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse())
);
createRulesBulkRoute(server.router, ml, isRuleRegistryEnabled, logger);
createRulesBulkRoute(server.router, ml, logger);
});
describe('status codes', () => {
@ -98,23 +93,10 @@ describe.each([
);
expect(response.status).toEqual(200);
if (!isRuleRegistryEnabled) {
expect(response.body).toEqual([
{
error: {
message:
'To create a rule, the index must exist first. Index undefined does not exist',
status_code: 400,
},
rule_id: 'rule-1',
},
]);
}
});
test('returns a duplicate error if rule_id already exists', async () => {
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const response = await server.inject(
getReadBulkRequest(),
requestContextMock.convertContext(context)

View file

@ -6,7 +6,6 @@
*/
import { validate } from '@kbn/securitysolution-io-ts-utils';
import { getIndexExists } from '@kbn/securitysolution-es-utils';
import { Logger } from '@kbn/core/server';
import { createRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/create_rules_type_dependents';
import { createRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request/create_rules_bulk_schema';
@ -34,7 +33,6 @@ import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from './ut
export const createRulesBulkRoute = (
router: SecuritySolutionPluginRouter,
ml: SetupPlugins['ml'],
isRuleRegistryEnabled: boolean,
logger: Logger
) => {
router.post(
@ -55,7 +53,6 @@ export const createRulesBulkRoute = (
const ctx = await context.resolve(['core', 'securitySolution', 'licensing', 'alerting']);
const rulesClient = ctx.alerting.getRulesClient();
const esClient = ctx.core.elasticsearch.client;
const savedObjectsClient = ctx.core.savedObjects.client;
const siemClient = ctx.securitySolution.getAppClient();
@ -76,7 +73,6 @@ export const createRulesBulkRoute = (
if (payloadRule.rule_id != null) {
const rule = await readRules({
id: undefined,
isRuleRegistryEnabled,
rulesClient,
ruleId: payloadRule.rule_id,
});
@ -88,11 +84,7 @@ export const createRulesBulkRoute = (
});
}
}
const internalRule = convertCreateAPIToInternalSchema(
payloadRule,
siemClient,
isRuleRegistryEnabled
);
const internalRule = convertCreateAPIToInternalSchema(payloadRule, siemClient);
try {
const validationErrors = createRuleValidateTypeDependents(payloadRule);
if (validationErrors.length) {
@ -104,15 +96,6 @@ export const createRulesBulkRoute = (
}
throwAuthzError(await mlAuthz.validateRuleType(internalRule.params.type));
const finalIndex = internalRule.params.outputIndex;
const indexExists = await getIndexExists(esClient.asCurrentUser, finalIndex);
if (!isRuleRegistryEnabled && !indexExists) {
return createBulkErrorObject({
ruleId: internalRule.params.ruleId,
statusCode: 400,
message: `To create a rule, the index must exist first. Index ${finalIndex} does not exist`,
});
}
const createdRule = await rulesClient.create({
data: internalRule,
@ -123,12 +106,7 @@ export const createRulesBulkRoute = (
await rulesClient.muteAll({ id: createdRule.id });
}
return transformValidateBulkError(
internalRule.params.ruleId,
createdRule,
null,
isRuleRegistryEnabled
);
return transformValidateBulkError(internalRule.params.ruleId, createdRule, null);
} catch (err) {
return transformBulkError(
internalRule.params.ruleId,

View file

@ -8,13 +8,12 @@
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import {
getEmptyFindResult,
getAlertMock,
getRuleMock,
getCreateRequest,
getRuleExecutionSummarySucceeded,
getFindResultWithSingleHit,
createMlRuleRequest,
getBasicEmptySearchResponse,
getBasicNoShardsSearchResponse,
} from '../__mocks__/request_responses';
import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks';
import { buildMlAuthz } from '../../../machine_learning/authz';
@ -27,10 +26,7 @@ import { getQueryRuleParams } from '../../schemas/rule_schemas.mock';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
describe.each([
['Legacy', false],
['RAC', true],
])('create_rules - %s', (_, isRuleRegistryEnabled) => {
describe('create_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.createSetupContract>;
@ -41,9 +37,7 @@ describe.each([
ml = mlServicesMock.createSetupContract();
clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); // no current rules
clients.rulesClient.create.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
); // creation succeeds
clients.rulesClient.create.mockResolvedValue(getRuleMock(getQueryRuleParams())); // creation succeeds
clients.ruleExecutionLog.getExecutionSummary.mockResolvedValue(
getRuleExecutionSummarySucceeded()
);
@ -51,7 +45,7 @@ describe.each([
context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue(
elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse())
);
createRulesRoute(server.router, ml, isRuleRegistryEnabled);
createRulesRoute(server.router, ml);
});
describe('status codes', () => {
@ -103,29 +97,8 @@ describe.each([
});
describe('unhappy paths', () => {
test('it returns a 400 if the index does not exist when rule registry not enabled', async () => {
context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValueOnce(
elasticsearchClientMock.createSuccessTransportRequestPromise(
getBasicNoShardsSearchResponse()
)
);
const response = await server.inject(
getCreateRequest(),
requestContextMock.convertContext(context)
);
expect(response.status).toEqual(isRuleRegistryEnabled ? 200 : 400);
if (!isRuleRegistryEnabled) {
expect(response.body).toEqual({
message: 'To create a rule, the index must exist first. Index undefined does not exist',
status_code: 400,
});
}
});
test('returns a duplicate error if rule_id already exists', async () => {
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const response = await server.inject(
getCreateRequest(),
requestContextMock.convertContext(context)

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { transformError, getIndexExists } from '@kbn/securitysolution-es-utils';
import { transformError } from '@kbn/securitysolution-es-utils';
import { buildRouteValidation } from '../../../../utils/build_validation/route_validation';
import {
DETECTION_ENGINE_RULES_URL,
@ -25,8 +25,7 @@ import { convertCreateAPIToInternalSchema } from '../../schemas/rule_converters'
export const createRulesRoute = (
router: SecuritySolutionPluginRouter,
ml: SetupPlugins['ml'],
isRuleRegistryEnabled: boolean
ml: SetupPlugins['ml']
): void => {
router.post(
{
@ -56,13 +55,11 @@ export const createRulesRoute = (
const rulesClient = ctx.alerting.getRulesClient();
const ruleExecutionLog = ctx.securitySolution.getRuleExecutionLog();
const esClient = ctx.core.elasticsearch.client;
const savedObjectsClient = ctx.core.savedObjects.client;
const siemClient = ctx.securitySolution.getAppClient();
if (request.body.rule_id != null) {
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
ruleId: request.body.rule_id,
id: undefined,
@ -75,11 +72,7 @@ export const createRulesRoute = (
}
}
const internalRule = convertCreateAPIToInternalSchema(
request.body,
siemClient,
isRuleRegistryEnabled
);
const internalRule = convertCreateAPIToInternalSchema(request.body, siemClient);
const mlAuthz = buildMlAuthz({
license: ctx.licensing.license,
@ -89,17 +82,6 @@ export const createRulesRoute = (
});
throwAuthzError(await mlAuthz.validateRuleType(internalRule.params.type));
const indexExists = await getIndexExists(
esClient.asCurrentUser,
internalRule.params.outputIndex
);
if (!isRuleRegistryEnabled && !indexExists) {
return siemResponse.error({
statusCode: 400,
body: `To create a rule, the index must exist first. Index ${internalRule.params.outputIndex} does not exist`,
});
}
// This will create the endpoint list if it does not exist yet
await ctx.lists?.getExceptionListClient().createEndpointList();
@ -114,11 +96,7 @@ export const createRulesRoute = (
const ruleExecutionSummary = await ruleExecutionLog.getExecutionSummary(createdRule.id);
const [validated, errors] = newTransformValidate(
createdRule,
ruleExecutionSummary,
isRuleRegistryEnabled
);
const [validated, errors] = newTransformValidate(createdRule, ruleExecutionSummary);
if (errors != null) {
return siemResponse.error({ statusCode: 500, body: errors });
} else {

View file

@ -19,10 +19,7 @@ import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { deleteRulesBulkRoute } from './delete_rules_bulk_route';
import { loggingSystemMock } from '@kbn/core/server/mocks';
describe.each([
['Legacy', false],
['RAC', true],
])('delete_rules - %s', (_, isRuleRegistryEnabled) => {
describe('delete_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
@ -31,11 +28,11 @@ describe.each([
({ clients, context } = requestContextMock.createTools());
const logger = loggingSystemMock.createLogger();
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled)); // rule exists
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // rule exists
clients.rulesClient.delete.mockResolvedValue({}); // successful deletion
clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse()); // rule status request
deleteRulesBulkRoute(server.router, isRuleRegistryEnabled, logger);
deleteRulesBulkRoute(server.router, logger);
});
describe('status codes with actionClient and alertClient', () => {

View file

@ -40,11 +40,7 @@ type Handler = RequestHandler<
/**
* @deprecated since version 8.2.0. Use the detection_engine/rules/_bulk_action API instead
*/
export const deleteRulesBulkRoute = (
router: SecuritySolutionPluginRouter,
isRuleRegistryEnabled: boolean,
logger: Logger
) => {
export const deleteRulesBulkRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
const config: Config = {
validate: {
body: buildRouteValidation<typeof queryRulesBulkSchema, QueryRulesBulkSchemaDecoded>(
@ -81,7 +77,7 @@ export const deleteRulesBulkRoute = (
}
try {
const rule = await readRules({ rulesClient, id, ruleId, isRuleRegistryEnabled });
const rule = await readRules({ rulesClient, id, ruleId });
const migratedRule = await legacyMigrate({
rulesClient,
savedObjectsClient,
@ -102,8 +98,7 @@ export const deleteRulesBulkRoute = (
return transformValidateBulkError(
idOrRuleIdOrUnknown,
migratedRule,
ruleExecutionSummary,
isRuleRegistryEnabled
ruleExecutionSummary
);
} catch (err) {
return transformBulkError(idOrRuleIdOrUnknown, err);

View file

@ -8,7 +8,7 @@
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import {
getEmptyFindResult,
resolveAlertMock,
resolveRuleMock,
getDeleteRequest,
getFindResultWithSingleHit,
getDeleteRequestById,
@ -18,10 +18,7 @@ import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { deleteRulesRoute } from './delete_rules_route';
import { getQueryRuleParams } from '../../schemas/rule_schemas.mock';
describe.each([
['Legacy', false],
['RAC', true],
])('delete_rules - %s', (_, isRuleRegistryEnabled) => {
describe('delete_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
@ -29,10 +26,10 @@ describe.each([
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse());
deleteRulesRoute(server.router, isRuleRegistryEnabled);
deleteRulesRoute(server.router);
});
describe('status codes with actionClient and alertClient', () => {
@ -46,9 +43,7 @@ describe.each([
});
test('returns 200 when deleting a single rule with a valid actionClient and alertClient by id', async () => {
clients.rulesClient.resolve.mockResolvedValue(
resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
);
clients.rulesClient.resolve.mockResolvedValue(resolveRuleMock(getQueryRuleParams()));
const response = await server.inject(
getDeleteRequestById(),
requestContextMock.convertContext(context)

View file

@ -21,10 +21,7 @@ import { buildSiemResponse } from '../utils';
import { readRules } from '../../rules/read_rules';
import { legacyMigrate } from '../../rules/utils';
export const deleteRulesRoute = (
router: SecuritySolutionPluginRouter,
isRuleRegistryEnabled: boolean
) => {
export const deleteRulesRoute = (router: SecuritySolutionPluginRouter) => {
router.delete(
{
path: DETECTION_ENGINE_RULES_URL,
@ -52,7 +49,7 @@ export const deleteRulesRoute = (
const ruleExecutionLog = ctx.securitySolution.getRuleExecutionLog();
const savedObjectsClient = ctx.core.savedObjects.client;
const rule = await readRules({ isRuleRegistryEnabled, rulesClient, id, ruleId });
const rule = await readRules({ rulesClient, id, ruleId });
const migratedRule = await legacyMigrate({
rulesClient,
savedObjectsClient,
@ -75,7 +72,7 @@ export const deleteRulesRoute = (
ruleExecutionLog,
});
const transformed = transform(migratedRule, ruleExecutionSummary, isRuleRegistryEnabled);
const transformed = transform(migratedRule, ruleExecutionSummary);
if (transformed == null) {
return siemResponse.error({ statusCode: 500, body: 'failed to transform alert' });
} else {

View file

@ -25,8 +25,7 @@ import { buildSiemResponse } from '../utils';
export const exportRulesRoute = (
router: SecuritySolutionPluginRouter,
config: ConfigType,
logger: Logger,
isRuleRegistryEnabled: boolean
logger: Logger
) => {
router.post(
{
@ -58,7 +57,6 @@ export const exportRulesRoute = (
});
} else {
const nonPackagedRulesCount = await getNonPackagedRulesCount({
isRuleRegistryEnabled,
rulesClient,
});
if (nonPackagedRulesCount > exportSizeLimit) {
@ -76,16 +74,9 @@ export const exportRulesRoute = (
exceptionsClient,
savedObjectsClient,
request.body.objects,
logger,
isRuleRegistryEnabled
logger
)
: await getExportAll(
rulesClient,
exceptionsClient,
savedObjectsClient,
logger,
isRuleRegistryEnabled
);
: await getExportAll(rulesClient, exceptionsClient, savedObjectsClient, logger);
const responseBody = request.query.exclude_export_details
? exportedRulesAndExceptions.rulesNdjson

View file

@ -10,7 +10,7 @@ import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { getQueryRuleParams } from '../../schemas/rule_schemas.mock';
import { requestContextMock, requestMock, serverMock } from '../__mocks__';
import {
getAlertMock,
getRuleMock,
getFindRequest,
getFindResultWithSingleHit,
getEmptySavedObjectsResponse,
@ -18,10 +18,7 @@ import {
} from '../__mocks__/request_responses';
import { findRulesRoute } from './find_rules_route';
describe.each([
['Legacy', false],
['RAC', true],
])('find_rules - %s', (_, isRuleRegistryEnabled) => {
describe('find_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
@ -31,16 +28,14 @@ describe.each([
logger = loggingSystemMock.createLogger();
({ clients, context } = requestContextMock.createTools());
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
clients.rulesClient.get.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
);
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
clients.rulesClient.get.mockResolvedValue(getRuleMock(getQueryRuleParams()));
clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse());
clients.ruleExecutionLog.getExecutionSummariesBulk.mockResolvedValue(
getRuleExecutionSummaries()
);
findRulesRoute(server.router, logger, isRuleRegistryEnabled);
findRulesRoute(server.router, logger);
});
describe('status codes', () => {

View file

@ -22,11 +22,7 @@ import { transformFindAlerts } from './utils';
// eslint-disable-next-line no-restricted-imports
import { legacyGetBulkRuleActionsSavedObject } from '../../rule_actions/legacy_get_bulk_rule_actions_saved_object';
export const findRulesRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger,
isRuleRegistryEnabled: boolean
) => {
export const findRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
router.get(
{
path: `${DETECTION_ENGINE_RULES_URL}/_find`,
@ -55,7 +51,6 @@ export const findRulesRoute = (
const savedObjectsClient = ctx.core.savedObjects.client;
const rules = await findRules({
isRuleRegistryEnabled,
rulesClient,
perPage: query.per_page,
page: query.page,

View file

@ -51,10 +51,7 @@ jest.mock('../../../timeline/utils/check_timelines_status', () => {
};
});
describe.each([
['Legacy', false],
['RAC', true],
])('get_prepackaged_rule_status_route - %s', (_, isRuleRegistryEnabled) => {
describe('get_prepackaged_rule_status_route', () => {
const mockGetCurrentUser = {
user: {
username: 'mockUser',
@ -85,12 +82,7 @@ describe.each([
prepackagedTimelines: [],
});
getPrepackagedRulesStatusRoute(
server.router,
createMockConfig(),
securitySetup,
isRuleRegistryEnabled
);
getPrepackagedRulesStatusRoute(server.router, createMockConfig(), securitySetup);
});
describe('status codes', () => {
@ -137,7 +129,7 @@ describe.each([
});
test('1 rule installed, 1 custom rules, 0 rules not installed, and 1 rule to not updated', async () => {
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const request = getPrepackagedRulesStatusRequest();
const response = await server.inject(request, requestContextMock.convertContext(context));

View file

@ -32,8 +32,7 @@ import {
export const getPrepackagedRulesStatusRoute = (
router: SecuritySolutionPluginRouter,
config: ConfigType,
security: SetupPlugins['security'],
isRuleRegistryEnabled: boolean
security: SetupPlugins['security']
) => {
router.get(
{
@ -57,7 +56,6 @@ export const getPrepackagedRulesStatusRoute = (
config.prebuiltRulesFromSavedObjects
);
const customRules = await findRules({
isRuleRegistryEnabled,
rulesClient,
perPage: 1,
page: 1,
@ -69,7 +67,6 @@ export const getPrepackagedRulesStatusRoute = (
const frameworkRequest = await buildFrameworkRequest(context, security, request);
const prepackagedRules = await getExistingPrepackagedRules({
rulesClient,
isRuleRegistryEnabled,
});
const rulesToInstall = getRulesToInstall(latestPrepackagedRules, prepackagedRules);

View file

@ -10,10 +10,9 @@ import {
getImportRulesRequest,
getImportRulesRequestOverwriteTrue,
getEmptyFindResult,
getAlertMock,
getRuleMock,
getFindResultWithSingleHit,
getBasicEmptySearchResponse,
getBasicNoShardsSearchResponse,
} from '../__mocks__/request_responses';
import { createMockConfig, requestContextMock, serverMock, requestMock } from '../__mocks__';
import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks';
@ -31,10 +30,7 @@ import { getQueryRuleParams } from '../../schemas/rule_schemas.mock';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
describe.each([
['Legacy', false],
['RAC', true],
])('import_rules_route - %s', (_, isRuleRegistryEnabled) => {
describe('import_rules_route', () => {
let config: ReturnType<typeof createMockConfig>;
let server: ReturnType<typeof serverMock.create>;
let request: ReturnType<typeof requestMock.create>;
@ -50,14 +46,12 @@ describe.each([
ml = mlServicesMock.createSetupContract();
clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); // no extant rules
clients.rulesClient.update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
);
clients.rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams()));
clients.actionsClient.getAll.mockResolvedValue([]);
context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue(
elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse())
);
importRulesRoute(server.router, config, ml, isRuleRegistryEnabled);
importRulesRoute(server.router, config, ml);
});
describe('status codes', () => {
@ -84,7 +78,7 @@ describe.each([
});
describe('unhappy paths', () => {
it('returns a 403 error object if ML Authz fails', async () => {
test('returns a 403 error object if ML Authz fails', async () => {
(buildMlAuthz as jest.Mock).mockReturnValueOnce({
validateRuleType: jest
.fn()
@ -124,39 +118,6 @@ describe.each([
transformMock.mockRestore();
});
test('returns an error if the index does not exist when rule registry not enabled', async () => {
clients.appClient.getSignalsIndex.mockReturnValue('mockSignalsIndex');
context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValueOnce(
elasticsearchClientMock.createSuccessTransportRequestPromise(
getBasicNoShardsSearchResponse()
)
);
const response = await server.inject(request, requestContextMock.convertContext(context));
expect(response.status).toEqual(isRuleRegistryEnabled ? 200 : 400);
if (!isRuleRegistryEnabled) {
expect(response.body).toEqual({
message:
'To create a rule, the index must exist first. Index mockSignalsIndex does not exist',
status_code: 400,
});
}
});
test('returns an error when cluster throws error', async () => {
context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue(
elasticsearchClientMock.createErrorTransportRequestPromise({
body: new Error('Test error'),
})
);
const response = await server.inject(request, requestContextMock.convertContext(context));
expect(response.status).toEqual(500);
expect(response.body).toEqual({
message: 'Test error',
status_code: 500,
});
});
test('returns 400 if file extension type is not .ndjson', async () => {
const requestPayload = buildHapiStream(ruleIdsToNdJsonString(['rule-1']), 'wrong.html');
const badRequest = getImportRulesRequest(requestPayload);
@ -169,9 +130,7 @@ describe.each([
describe('single rule import', () => {
test('returns 200 if rule imported successfully', async () => {
clients.rulesClient.create.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
);
clients.rulesClient.create.mockResolvedValue(getRuleMock(getQueryRuleParams()));
const response = await server.inject(request, requestContextMock.convertContext(context));
expect(response.status).toEqual(200);
expect(response.body).toEqual({
@ -210,9 +169,7 @@ describe.each([
describe('rule with existing rule_id', () => {
test('returns with reported conflict if `overwrite` is set to `false`', async () => {
clients.rulesClient.find.mockResolvedValue(
getFindResultWithSingleHit(isRuleRegistryEnabled)
); // extant rule
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // extant rule
const response = await server.inject(request, requestContextMock.convertContext(context));
expect(response.status).toEqual(200);
@ -235,9 +192,7 @@ describe.each([
});
test('returns with NO reported conflict if `overwrite` is set to `true`', async () => {
clients.rulesClient.find.mockResolvedValue(
getFindResultWithSingleHit(isRuleRegistryEnabled)
); // extant rule
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // extant rule
const overwriteRequest = getImportRulesRequestOverwriteTrue(
buildHapiStream(ruleIdsToNdJsonString(['rule-1']))
);
@ -390,9 +345,7 @@ describe.each([
describe('rules with existing rule_id', () => {
beforeEach(() => {
clients.rulesClient.find.mockResolvedValueOnce(
getFindResultWithSingleHit(isRuleRegistryEnabled)
); // extant rule
clients.rulesClient.find.mockResolvedValueOnce(getFindResultWithSingleHit()); // extant rule
});
test('returns with reported conflict if `overwrite` is set to `false`', async () => {

View file

@ -10,7 +10,7 @@ import { extname } from 'path';
import { schema } from '@kbn/config-schema';
import { createPromiseFromStreams } from '@kbn/utils';
import { transformError, getIndexExists } from '@kbn/securitysolution-es-utils';
import { transformError } from '@kbn/securitysolution-es-utils';
import { validate } from '@kbn/securitysolution-io-ts-utils';
import { ImportQuerySchemaDecoded, importQuerySchema } from '@kbn/securitysolution-io-ts-types';
@ -52,8 +52,7 @@ const CHUNK_PARSED_OBJECT_SIZE = 50;
export const importRulesRoute = (
router: SecuritySolutionPluginRouter,
config: ConfigType,
ml: SetupPlugins['ml'],
isRuleRegistryEnabled: boolean
ml: SetupPlugins['ml']
) => {
router.post(
{
@ -87,12 +86,10 @@ export const importRulesRoute = (
const rulesClient = ctx.alerting.getRulesClient();
const actionsClient = ctx.actions.getActionsClient();
const esClient = ctx.core.elasticsearch.client;
const actionSOClient = ctx.core.savedObjects.getClient({
includedHiddenTypes: ['action'],
});
const savedObjectsClient = ctx.core.savedObjects.client;
const siemClient = ctx.securitySolution.getAppClient();
const exceptionsClient = ctx.lists?.getExceptionListClient();
const mlAuthz = buildMlAuthz({
@ -111,14 +108,6 @@ export const importRulesRoute = (
});
}
const signalsIndex = siemClient.getSignalsIndex();
const indexExists = await getIndexExists(esClient.asCurrentUser, signalsIndex);
if (!isRuleRegistryEnabled && !indexExists) {
return siemResponse.error({
statusCode: 400,
body: `To create a rule, the index must exist first. Index ${signalsIndex} does not exist`,
});
}
const objectLimit = config.maxRuleImportExportSize;
// parse file to separate out exceptions from rules
@ -180,9 +169,7 @@ export const importRulesRoute = (
rulesClient,
savedObjectsClient,
exceptionsClient,
isRuleRegistryEnabled,
spaceId: ctx.securitySolution.getSpaceId(),
signalsIndex,
existingLists: foundReferencedExceptionLists,
});

View file

@ -15,7 +15,7 @@ import {
getEmptyFindResult,
getFindResultWithSingleHit,
getPatchBulkRequest,
getAlertMock,
getRuleMock,
typicalMlRulePayload,
} from '../__mocks__/request_responses';
import { serverMock, requestContextMock, requestMock } from '../__mocks__';
@ -26,10 +26,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
describe.each([
['Legacy', false],
['RAC', true],
])('patch_rules_bulk - %s', (_, isRuleRegistryEnabled) => {
describe('patch_rules_bulk', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.createSetupContract>;
@ -40,12 +37,10 @@ describe.each([
ml = mlServicesMock.createSetupContract();
const logger = loggingSystemMock.createLogger();
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled)); // rule exists
clients.rulesClient.update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
); // update succeeds
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // rule exists
clients.rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); // update succeeds
patchRulesBulkRoute(server.router, ml, isRuleRegistryEnabled, logger);
patchRulesBulkRoute(server.router, ml, logger);
});
describe('status codes', () => {

View file

@ -34,7 +34,6 @@ import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from './ut
export const patchRulesBulkRoute = (
router: SecuritySolutionPluginRouter,
ml: SetupPlugins['ml'],
isRuleRegistryEnabled: boolean,
logger: Logger
) => {
router.patch(
@ -131,7 +130,6 @@ export const patchRulesBulkRoute = (
}
const existingRule = await readRules({
isRuleRegistryEnabled,
rulesClient,
ruleId,
id,
@ -200,12 +198,7 @@ export const patchRulesBulkRoute = (
});
if (rule != null && rule.enabled != null && rule.name != null) {
const ruleExecutionSummary = await ruleExecutionLog.getExecutionSummary(rule.id);
return transformValidateBulkError(
rule.id,
rule,
ruleExecutionSummary,
isRuleRegistryEnabled
);
return transformValidateBulkError(rule.id, rule, ruleExecutionSummary);
} else {
return getIdBulkError({ id, ruleId });
}

View file

@ -11,7 +11,7 @@ import { buildMlAuthz } from '../../../machine_learning/authz';
import {
getEmptyFindResult,
getRuleExecutionSummarySucceeded,
getAlertMock,
getRuleMock,
getPatchRequest,
getFindResultWithSingleHit,
nonRuleFindResult,
@ -24,10 +24,7 @@ import { getQueryRuleParams } from '../../schemas/rule_schemas.mock';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
describe.each([
['Legacy', false],
['RAC', true],
])('patch_rules - %s', (_, isRuleRegistryEnabled) => {
describe('patch_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.createSetupContract>;
@ -37,18 +34,14 @@ describe.each([
({ clients, context } = requestContextMock.createTools());
ml = mlServicesMock.createSetupContract();
clients.rulesClient.get.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
); // existing rule
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled)); // existing rule
clients.rulesClient.update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
); // successful update
clients.rulesClient.get.mockResolvedValue(getRuleMock(getQueryRuleParams())); // existing rule
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // existing rule
clients.rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); // successful update
clients.ruleExecutionLog.getExecutionSummary.mockResolvedValue(
getRuleExecutionSummarySucceeded()
);
patchRulesRoute(server.router, ml, isRuleRegistryEnabled);
patchRulesRoute(server.router, ml);
});
describe('status codes', () => {
@ -74,7 +67,7 @@ describe.each([
});
test('returns error if requesting a non-rule', async () => {
clients.rulesClient.find.mockResolvedValue(nonRuleFindResult(isRuleRegistryEnabled));
clients.rulesClient.find.mockResolvedValue(nonRuleFindResult());
const response = await server.inject(
getPatchRequest(),
requestContextMock.convertContext(context)

View file

@ -27,11 +27,7 @@ import { readRules } from '../../rules/read_rules';
import { legacyMigrate } from '../../rules/utils';
import { PartialFilter } from '../../types';
export const patchRulesRoute = (
router: SecuritySolutionPluginRouter,
ml: SetupPlugins['ml'],
isRuleRegistryEnabled: boolean
) => {
export const patchRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => {
router.patch(
{
path: DETECTION_ENGINE_RULES_URL,
@ -122,7 +118,6 @@ export const patchRulesRoute = (
}
const existingRule = await readRules({
isRuleRegistryEnabled,
rulesClient,
ruleId,
id,
@ -192,11 +187,7 @@ export const patchRulesRoute = (
if (rule != null && rule.enabled != null && rule.name != null) {
const ruleExecutionSummary = await ruleExecutionLog.getExecutionSummary(rule.id);
const [validated, errors] = transformValidate(
rule,
ruleExecutionSummary,
isRuleRegistryEnabled
);
const [validated, errors] = transformValidate(rule, ruleExecutionSummary);
if (errors != null) {
return siemResponse.error({ statusCode: 500, body: errors });
} else {

View file

@ -27,24 +27,21 @@ import { readRules } from '../../rules/read_rules';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
jest.mock('../../rules/read_rules', () => ({ readRules: jest.fn() }));
describe.each([
['Legacy', false],
['RAC', true],
])('perform_bulk_action - %s', (_, isRuleRegistryEnabled) => {
describe('perform_bulk_action', () => {
const readRulesMock = readRules as jest.Mock;
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.createSetupContract>;
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
const mockRule = getFindResultWithSingleHit(isRuleRegistryEnabled).data[0];
const mockRule = getFindResultWithSingleHit().data[0];
beforeEach(() => {
server = serverMock.create();
logger = loggingSystemMock.createLogger();
({ clients, context } = requestContextMock.createTools());
ml = mlServicesMock.createSetupContract();
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
performBulkActionRoute(server.router, ml, logger, isRuleRegistryEnabled);
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
performBulkActionRoute(server.router, ml, logger);
});
describe('status codes', () => {

View file

@ -146,13 +146,11 @@ const fetchRulesByQueryOrIds = async ({
query,
ids,
rulesClient,
isRuleRegistryEnabled,
abortSignal,
}: {
query: string | undefined;
ids: string[] | undefined;
rulesClient: RulesClient;
isRuleRegistryEnabled: boolean;
abortSignal: AbortSignal;
}): Promise<PromisePoolOutcome<string, RuleAlertType>> => {
if (ids) {
@ -160,7 +158,7 @@ const fetchRulesByQueryOrIds = async ({
concurrency: MAX_RULES_TO_UPDATE_IN_PARALLEL,
items: ids,
executor: async (id: string) => {
const rule = await readRules({ id, rulesClient, isRuleRegistryEnabled, ruleId: undefined });
const rule = await readRules({ id, rulesClient, ruleId: undefined });
if (rule == null) {
throw Error('Rule not found');
}
@ -171,7 +169,6 @@ const fetchRulesByQueryOrIds = async ({
}
const { data, total } = await findRules({
isRuleRegistryEnabled,
rulesClient,
perPage: MAX_RULES_TO_PROCESS_TOTAL,
filter: query !== '' ? query : undefined,
@ -229,8 +226,7 @@ export const migrateRuleActions = async ({
export const performBulkActionRoute = (
router: SecuritySolutionPluginRouter,
ml: SetupPlugins['ml'],
logger: Logger,
isRuleRegistryEnabled: boolean
logger: Logger
) => {
router.post(
{
@ -291,7 +287,6 @@ export const performBulkActionRoute = (
});
const fetchRulesOutcome = await fetchRulesByQueryOrIds({
isRuleRegistryEnabled,
rulesClient,
query: body.query,
ids: body.ids,
@ -386,7 +381,7 @@ export const performBulkActionRoute = (
throwAuthzError(await mlAuthz.validateRuleType(migratedRule.params.type));
const createdRule = await rulesClient.create({
data: duplicateRule(migratedRule, isRuleRegistryEnabled),
data: duplicateRule(migratedRule),
});
return createdRule;
@ -400,8 +395,7 @@ export const performBulkActionRoute = (
exceptionsClient,
savedObjectsClient,
rules.map(({ params }) => ({ rule_id: params.ruleId })),
logger,
isRuleRegistryEnabled
logger
);
const responseBody = `${exported.rulesNdjson}${exported.exceptionLists}${exported.exportDetails}`;

View file

@ -104,7 +104,7 @@ export const previewRulesRoute = async (
});
}
const internalRule = convertCreateAPIToInternalSchema(request.body, siemClient, false);
const internalRule = convertCreateAPIToInternalSchema(request.body, siemClient);
const previewRuleParams = internalRule.params;
const mlAuthz = buildMlAuthz({

View file

@ -17,15 +17,12 @@ import {
nonRuleFindResult,
getEmptySavedObjectsResponse,
getRuleExecutionSummarySucceeded,
resolveAlertMock,
resolveRuleMock,
} from '../__mocks__/request_responses';
import { requestMock, requestContextMock, serverMock } from '../__mocks__';
import { getQueryRuleParams } from '../../schemas/rule_schemas.mock';
describe.each([
['Legacy', false],
['RAC', true],
])('read_rules - %s', (_, isRuleRegistryEnabled) => {
describe('read_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
@ -36,19 +33,19 @@ describe.each([
logger = loggingSystemMock.createLogger();
({ clients, context } = requestContextMock.createTools());
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled)); // rule exists
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // rule exists
clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse()); // successful transform
clients.ruleExecutionLog.getExecutionSummary.mockResolvedValue(
getRuleExecutionSummarySucceeded()
);
clients.rulesClient.resolve.mockResolvedValue({
...resolveAlertMock(isRuleRegistryEnabled, {
...resolveRuleMock({
...getQueryRuleParams(),
}),
id: myFakeId,
});
readRulesRoute(server.router, logger, isRuleRegistryEnabled);
readRulesRoute(server.router, logger);
});
describe('status codes', () => {
@ -70,7 +67,7 @@ describe.each([
test('returns 200 when reading a single rule outcome === aliasMatch', async () => {
clients.rulesClient.resolve.mockResolvedValue({
...resolveAlertMock(isRuleRegistryEnabled, {
...resolveRuleMock({
...getQueryRuleParams(),
}),
id: myFakeId,
@ -85,7 +82,7 @@ describe.each([
test('returns 200 when reading a single rule outcome === conflict', async () => {
clients.rulesClient.resolve.mockResolvedValue({
...resolveAlertMock(isRuleRegistryEnabled, {
...resolveRuleMock({
...getQueryRuleParams(),
}),
id: myFakeId,
@ -101,7 +98,7 @@ describe.each([
});
test('returns error if requesting a non-rule', async () => {
clients.rulesClient.find.mockResolvedValue(nonRuleFindResult(isRuleRegistryEnabled));
clients.rulesClient.find.mockResolvedValue(nonRuleFindResult());
const response = await server.inject(
getReadRequest(),
requestContextMock.convertContext(context)

View file

@ -22,11 +22,7 @@ import { readRules } from '../../rules/read_rules';
// eslint-disable-next-line no-restricted-imports
import { legacyGetRuleActionsSavedObject } from '../../rule_actions/legacy_get_rule_actions_saved_object';
export const readRulesRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger,
isRuleRegistryEnabled: boolean
) => {
export const readRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
router.get(
{
path: DETECTION_ENGINE_RULES_URL,
@ -55,7 +51,6 @@ export const readRulesRoute = (
const rule = await readRules({
id,
isRuleRegistryEnabled,
rulesClient,
ruleId,
});
@ -68,12 +63,7 @@ export const readRulesRoute = (
const ruleExecutionSummary = await ruleExecutionLog.getExecutionSummary(rule.id);
const transformed = transform(
rule,
ruleExecutionSummary,
isRuleRegistryEnabled,
legacyRuleActions
);
const transformed = transform(rule, ruleExecutionSummary, legacyRuleActions);
if (transformed == null) {
return siemResponse.error({ statusCode: 500, body: 'Internal error transforming' });
} else {

View file

@ -10,7 +10,7 @@ import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../mach
import { buildMlAuthz } from '../../../machine_learning/authz';
import {
getEmptyFindResult,
getAlertMock,
getRuleMock,
getFindResultWithSingleHit,
getUpdateBulkRequest,
typicalMlRulePayload,
@ -24,10 +24,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
describe.each([
['Legacy', false],
['RAC', true],
])('update_rules_bulk - %s', (_, isRuleRegistryEnabled) => {
describe('update_rules_bulk', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.createSetupContract>;
@ -38,14 +35,12 @@ describe.each([
ml = mlServicesMock.createSetupContract();
const logger = loggingSystemMock.createLogger();
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
clients.rulesClient.update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
);
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
clients.rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams()));
clients.appClient.getSignalsIndex.mockReturnValue('.siem-signals-test-index');
updateRulesBulkRoute(server.router, ml, isRuleRegistryEnabled, logger);
updateRulesBulkRoute(server.router, ml, logger);
});
describe('status codes', () => {

View file

@ -30,7 +30,6 @@ import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from './ut
export const updateRulesBulkRoute = (
router: SecuritySolutionPluginRouter,
ml: SetupPlugins['ml'],
isRuleRegistryEnabled: boolean,
logger: Logger
) => {
router.put(
@ -78,7 +77,6 @@ export const updateRulesBulkRoute = (
throwAuthzError(await mlAuthz.validateRuleType(payloadRule.type));
const existingRule = await readRules({
isRuleRegistryEnabled,
rulesClient,
ruleId: payloadRule.rule_id,
id: payloadRule.id,
@ -98,12 +96,7 @@ export const updateRulesBulkRoute = (
});
if (rule != null) {
const ruleExecutionSummary = await ruleExecutionLog.getExecutionSummary(rule.id);
return transformValidateBulkError(
rule.id,
rule,
ruleExecutionSummary,
isRuleRegistryEnabled
);
return transformValidateBulkError(rule.id, rule, ruleExecutionSummary);
} else {
return getIdBulkError({ id: payloadRule.id, ruleId: payloadRule.rule_id });
}

View file

@ -9,7 +9,7 @@ import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../mach
import { buildMlAuthz } from '../../../machine_learning/authz';
import {
getEmptyFindResult,
getAlertMock,
getRuleMock,
getUpdateRequest,
getFindResultWithSingleHit,
getRuleExecutionSummarySucceeded,
@ -24,10 +24,7 @@ import { getQueryRuleParams } from '../../schemas/rule_schemas.mock';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
describe.each([
['Legacy', false],
['RAC', true],
])('update_rules - %s', (_, isRuleRegistryEnabled) => {
describe('update_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.createSetupContract>;
@ -37,19 +34,15 @@ describe.each([
({ clients, context } = requestContextMock.createTools());
ml = mlServicesMock.createSetupContract();
clients.rulesClient.get.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
); // existing rule
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled)); // rule exists
clients.rulesClient.update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
); // successful update
clients.rulesClient.get.mockResolvedValue(getRuleMock(getQueryRuleParams())); // existing rule
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // rule exists
clients.rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); // successful update
clients.ruleExecutionLog.getExecutionSummary.mockResolvedValue(
getRuleExecutionSummarySucceeded()
);
clients.appClient.getSignalsIndex.mockReturnValue('.siem-signals-test-index');
updateRulesRoute(server.router, ml, isRuleRegistryEnabled);
updateRulesRoute(server.router, ml);
});
describe('status codes', () => {
@ -76,7 +69,7 @@ describe.each([
});
test('returns error when updating non-rule', async () => {
clients.rulesClient.find.mockResolvedValue(nonRuleFindResult(isRuleRegistryEnabled));
clients.rulesClient.find.mockResolvedValue(nonRuleFindResult());
const response = await server.inject(
getUpdateRequest(),
requestContextMock.convertContext(context)

View file

@ -22,11 +22,7 @@ import { buildRouteValidation } from '../../../../utils/build_validation/route_v
import { legacyMigrate } from '../../rules/utils';
import { readRules } from '../../rules/read_rules';
export const updateRulesRoute = (
router: SecuritySolutionPluginRouter,
ml: SetupPlugins['ml'],
isRuleRegistryEnabled: boolean
) => {
export const updateRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => {
router.put(
{
path: DETECTION_ENGINE_RULES_URL,
@ -59,7 +55,6 @@ export const updateRulesRoute = (
throwAuthzError(await mlAuthz.validateRuleType(request.body.type));
const existingRule = await readRules({
isRuleRegistryEnabled,
rulesClient,
ruleId: request.body.rule_id,
id: request.body.id,
@ -80,11 +75,7 @@ export const updateRulesRoute = (
if (rule != null) {
const ruleExecutionLog = ctx.securitySolution.getRuleExecutionLog();
const ruleExecutionSummary = await ruleExecutionLog.getExecutionSummary(rule.id);
const [validated, errors] = transformValidate(
rule,
ruleExecutionSummary,
isRuleRegistryEnabled
);
const [validated, errors] = transformValidate(rule, ruleExecutionSummary);
if (errors != null) {
return siemResponse.error({ statusCode: 500, body: errors });
} else {

View file

@ -22,7 +22,7 @@ import {
swapActionIds,
migrateLegacyActionsIds,
} from './utils';
import { getAlertMock } from '../__mocks__/request_responses';
import { getRuleMock } from '../__mocks__/request_responses';
import { INTERNAL_IDENTIFIER } from '../../../../../common/constants';
import { PartialFilter } from '../../types';
import { BulkError, createBulkErrorObject } from '../utils';
@ -64,21 +64,18 @@ const createMockImportRule = async (rule: ReturnType<typeof getCreateRulesSchema
return rules;
};
describe.each([
['Legacy', false],
['RAC', true],
])('utils - %s', (_, isRuleRegistryEnabled) => {
describe('utils', () => {
const { clients } = requestContextMock.createTools();
describe('internalRuleToAPIResponse', () => {
test('should work with a full data set', () => {
const fullRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const fullRule = getRuleMock(getQueryRuleParams());
const rule = internalRuleToAPIResponse(fullRule);
expect(rule).toEqual(getOutputRuleAlertForRest());
});
test('should omit note if note is undefined', () => {
const fullRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const fullRule = getRuleMock(getQueryRuleParams());
fullRule.params.note = undefined;
const rule = internalRuleToAPIResponse(fullRule);
const { note, ...expectedWithoutNote } = getOutputRuleAlertForRest();
@ -86,7 +83,7 @@ describe.each([
});
test('should return enabled is equal to false', () => {
const fullRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const fullRule = getRuleMock(getQueryRuleParams());
fullRule.enabled = false;
const ruleWithEnabledFalse = internalRuleToAPIResponse(fullRule);
const expected = getOutputRuleAlertForRest();
@ -95,7 +92,7 @@ describe.each([
});
test('should return immutable is equal to false', () => {
const fullRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const fullRule = getRuleMock(getQueryRuleParams());
fullRule.params.immutable = false;
const ruleWithEnabledFalse = internalRuleToAPIResponse(fullRule);
const expected = getOutputRuleAlertForRest();
@ -103,7 +100,7 @@ describe.each([
});
test('should work with tags but filter out any internal tags', () => {
const fullRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const fullRule = getRuleMock(getQueryRuleParams());
fullRule.tags = ['tag 1', 'tag 2', `${INTERNAL_IDENTIFIER}_some_other_value`];
const rule = internalRuleToAPIResponse(fullRule);
const expected = getOutputRuleAlertForRest();
@ -112,7 +109,7 @@ describe.each([
});
test('transforms ML Rule fields', () => {
const mlRule = getAlertMock(isRuleRegistryEnabled, getMlRuleParams());
const mlRule = getRuleMock(getMlRuleParams());
mlRule.params.anomalyThreshold = 55;
mlRule.params.machineLearningJobId = ['some_job_id'];
mlRule.params.type = 'machine_learning';
@ -128,7 +125,7 @@ describe.each([
});
test('transforms threat_matching fields', () => {
const threatRule = getAlertMock(isRuleRegistryEnabled, getThreatRuleParams());
const threatRule = getRuleMock(getThreatRuleParams());
const threatFilters: PartialFilter[] = [
{
query: {
@ -181,7 +178,7 @@ describe.each([
test('does not leak a lists structure in the transform which would cause validation issues', () => {
const result: RuleAlertType & { lists: [] } = {
lists: [],
...getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
...getRuleMock(getQueryRuleParams()),
};
const rule = internalRuleToAPIResponse(result);
expect(rule).toEqual(
@ -196,7 +193,7 @@ describe.each([
test('does not leak an exceptions_list structure in the transform which would cause validation issues', () => {
const result: RuleAlertType & { exceptions_list: [] } = {
exceptions_list: [],
...getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
...getRuleMock(getQueryRuleParams()),
};
const rule = internalRuleToAPIResponse(result);
expect(rule).toEqual(
@ -293,7 +290,7 @@ describe.each([
page: 1,
perPage: 0,
total: 0,
data: [getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())],
data: [getRuleMock(getQueryRuleParams())],
},
{},
{}
@ -313,7 +310,7 @@ describe.each([
page: 1,
perPage: 0,
total: 0,
data: [getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())],
data: [getRuleMock(getQueryRuleParams())],
},
{},
{
@ -340,7 +337,7 @@ describe.each([
];
const legacyRuleActions: Record<string, LegacyRulesActionsSavedObject | undefined> = {
[getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()).id]: {
[getRuleMock(getQueryRuleParams()).id]: {
id: '123',
actions,
alertThrottle: '1h',
@ -352,7 +349,7 @@ describe.each([
page: 1,
perPage: 0,
total: 0,
data: [getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())],
data: [getRuleMock(getQueryRuleParams())],
},
{},
legacyRuleActions
@ -373,18 +370,14 @@ describe.each([
describe('transform', () => {
test('outputs 200 if the data is of type siem alert', () => {
const output = transform(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
undefined,
isRuleRegistryEnabled
);
const output = transform(getRuleMock(getQueryRuleParams()), undefined);
const expected = getOutputRuleAlertForRest();
expect(output).toEqual(expected);
});
test('returns 500 if the data is not of type siem alert', () => {
const unsafeCast = { data: [{ random: 1 }] } as unknown as PartialRule;
const output = transform(unsafeCast, undefined, isRuleRegistryEnabled);
const output = transform(unsafeCast, undefined);
expect(output).toBeNull();
});
});
@ -496,15 +489,15 @@ describe.each([
});
test('given single alert will return the alert transformed', () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
const transformed = transformAlertsToRules([result1], {});
const expected = getOutputRuleAlertForRest();
expect(transformed).toEqual([expected]);
});
test('given two alerts will return the two alerts transformed', () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = 'some other id';
result2.params.ruleId = 'some other id';

View file

@ -123,10 +123,9 @@ export const transformFindAlerts = (
export const transform = (
rule: PartialRule<RuleParams>,
ruleExecutionSummary?: RuleExecutionSummary | null,
isRuleRegistryEnabled?: boolean,
legacyRuleActions?: LegacyRulesActionsSavedObject | null
): Partial<RulesSchema> | null => {
if (isAlertType(isRuleRegistryEnabled ?? false, rule)) {
if (isAlertType(rule)) {
return internalRuleToAPIResponse(rule, ruleExecutionSummary, legacyRuleActions);
}

View file

@ -8,7 +8,7 @@
import { requestContextMock } from '../../__mocks__';
import { importRules } from './import_rules_utils';
import {
getAlertMock,
getRuleMock,
getEmptyFindResult,
getFindResultWithSingleHit,
} from '../../__mocks__/request_responses';
@ -30,7 +30,7 @@ describe('importRules', () => {
beforeEach(() => {
clients.rulesClient.find.mockResolvedValue(getEmptyFindResult());
clients.rulesClient.update.mockResolvedValue(getAlertMock(true, getQueryRuleParams()));
clients.rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams()));
clients.actionsClient.getAll.mockResolvedValue([]);
jest.clearAllMocks();
@ -42,12 +42,10 @@ describe('importRules', () => {
rulesResponseAcc: [],
mlAuthz,
overwriteRules: false,
isRuleRegistryEnabled: true,
savedObjectsClient: context.core.savedObjects.client,
rulesClient: context.alerting.getRulesClient(),
exceptionsClient: context.lists?.getExceptionListClient(),
spaceId: 'default',
signalsIndex: '.signals-index',
existingLists: {},
});
@ -60,12 +58,10 @@ describe('importRules', () => {
rulesResponseAcc: [],
mlAuthz,
overwriteRules: false,
isRuleRegistryEnabled: true,
savedObjectsClient: context.core.savedObjects.client,
rulesClient: context.alerting.getRulesClient(),
exceptionsClient: context.lists?.getExceptionListClient(),
spaceId: 'default',
signalsIndex: '.signals-index',
existingLists: {},
});
@ -93,12 +89,10 @@ describe('importRules', () => {
rulesResponseAcc: [],
mlAuthz,
overwriteRules: false,
isRuleRegistryEnabled: true,
savedObjectsClient: context.core.savedObjects.client,
rulesClient: context.alerting.getRulesClient(),
exceptionsClient: context.lists?.getExceptionListClient(),
spaceId: 'default',
signalsIndex: '.signals-index',
existingLists: {},
});
@ -108,7 +102,7 @@ describe('importRules', () => {
});
it('reports error if "overwriteRules" is "false" and matching rule found', async () => {
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(true));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const result = await importRules({
ruleChunks: [
@ -122,12 +116,10 @@ describe('importRules', () => {
rulesResponseAcc: [],
mlAuthz,
overwriteRules: false,
isRuleRegistryEnabled: true,
savedObjectsClient: context.core.savedObjects.client,
rulesClient: context.alerting.getRulesClient(),
exceptionsClient: context.lists?.getExceptionListClient(),
spaceId: 'default',
signalsIndex: '.signals-index',
existingLists: {},
});
@ -142,7 +134,7 @@ describe('importRules', () => {
});
it('patches rule if "overwriteRules" is "true" and matching rule found', async () => {
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(true));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const result = await importRules({
ruleChunks: [
@ -156,12 +148,10 @@ describe('importRules', () => {
rulesResponseAcc: [],
mlAuthz,
overwriteRules: true,
isRuleRegistryEnabled: true,
savedObjectsClient: context.core.savedObjects.client,
rulesClient: context.alerting.getRulesClient(),
exceptionsClient: context.lists?.getExceptionListClient(),
spaceId: 'default',
signalsIndex: '.signals-index',
existingLists: {},
});
@ -185,12 +175,10 @@ describe('importRules', () => {
rulesResponseAcc: [],
mlAuthz,
overwriteRules: true,
isRuleRegistryEnabled: true,
savedObjectsClient: context.core.savedObjects.client,
rulesClient: context.alerting.getRulesClient(),
exceptionsClient: context.lists?.getExceptionListClient(),
spaceId: 'default',
signalsIndex: '.signals-index',
existingLists: {},
});
@ -222,12 +210,10 @@ describe('importRules', () => {
rulesResponseAcc: [],
mlAuthz,
overwriteRules: false,
isRuleRegistryEnabled: true,
savedObjectsClient: context.core.savedObjects.client,
rulesClient: context.alerting.getRulesClient(),
exceptionsClient: context.lists?.getExceptionListClient(),
spaceId: 'default',
signalsIndex: '.signals-index',
existingLists: {},
});
@ -244,7 +230,7 @@ describe('importRules', () => {
it('reports error if "patchRules" throws', async () => {
(patchRules as jest.Mock).mockRejectedValue(new Error('error patching rule'));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(true));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const result = await importRules({
ruleChunks: [
@ -258,12 +244,10 @@ describe('importRules', () => {
rulesResponseAcc: [],
mlAuthz,
overwriteRules: true,
isRuleRegistryEnabled: true,
savedObjectsClient: context.core.savedObjects.client,
rulesClient: context.alerting.getRulesClient(),
exceptionsClient: context.lists?.getExceptionListClient(),
spaceId: 'default',
signalsIndex: '.signals-index',
existingLists: {},
});

View file

@ -41,13 +41,10 @@ export interface RuleExceptionsPromiseFromStreams {
* @param mlAuthz {object}
* @param overwriteRules {boolean} - whether to overwrite existing rules
* with imported rules if their rule_id matches
* @param isRuleRegistryEnabled {boolean} - feature flag that should be
* removed as this is now on and no going back
* @param rulesClient {object}
* @param savedObjectsClient {object}
* @param exceptionsClient {object}
* @param spaceId {string} - space being used during import
* @param signalsIndex {string} - the signals index name
* @param existingLists {object} - all exception lists referenced by
* rules that were found to exist
* @returns {Promise} an array of error and success messages from import
@ -57,24 +54,20 @@ export const importRules = async ({
rulesResponseAcc,
mlAuthz,
overwriteRules,
isRuleRegistryEnabled,
rulesClient,
savedObjectsClient,
exceptionsClient,
spaceId,
signalsIndex,
existingLists,
}: {
ruleChunks: PromiseFromStreams[][];
rulesResponseAcc: ImportRuleResponse[];
mlAuthz: MlAuthz;
overwriteRules: boolean;
isRuleRegistryEnabled: boolean;
rulesClient: RulesClient;
savedObjectsClient: SavedObjectsClientContract;
exceptionsClient: ExceptionListClient | undefined;
spaceId: string;
signalsIndex: string;
existingLists: Record<string, ExceptionListSchema>;
}) => {
let importRuleResponse: ImportRuleResponse[] = [...rulesResponseAcc];
@ -167,7 +160,6 @@ export const importRules = async ({
const filters: PartialFilter[] | undefined = filtersRest as PartialFilter[];
throwAuthzError(await mlAuthz.validateRuleType(type));
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
ruleId,
id: undefined,
@ -175,7 +167,6 @@ export const importRules = async ({
if (rule == null) {
await createRules({
isRuleRegistryEnabled,
rulesClient,
anomalyThreshold,
author,
@ -190,7 +181,7 @@ export const importRules = async ({
language,
license,
machineLearningJobId,
outputIndex: signalsIndex,
outputIndex: '',
savedId,
timelineId,
timelineTitle,

View file

@ -8,7 +8,7 @@
import { transformValidate, transformValidateBulkError } from './validate';
import { BulkError } from '../utils';
import { RulesSchema } from '../../../../../common/detection_engine/schemas/response';
import { getAlertMock, getRuleExecutionSummarySucceeded } from '../__mocks__/request_responses';
import { getRuleMock, getRuleExecutionSummarySucceeded } from '../__mocks__/request_responses';
import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock';
import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock';
import { getQueryRuleParams } from '../../schemas/rule_schemas.mock';
@ -65,23 +65,20 @@ export const ruleOutput = (): RulesSchema => ({
timeline_id: 'some-timeline-id',
});
describe.each([
['Legacy', false],
['RAC', true],
])('validate - %s', (_, isRuleRegistryEnabled) => {
describe('validate', () => {
describe('transformValidate', () => {
test('it should do a validation correctly of a partial alert', () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const [validated, errors] = transformValidate(ruleAlert, null, isRuleRegistryEnabled);
const ruleAlert = getRuleMock(getQueryRuleParams());
const [validated, errors] = transformValidate(ruleAlert, null);
expect(validated).toEqual(ruleOutput());
expect(errors).toEqual(null);
});
test('it should do an in-validation correctly of a partial alert', () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
// @ts-expect-error
delete ruleAlert.name;
const [validated, errors] = transformValidate(ruleAlert, null, isRuleRegistryEnabled);
const [validated, errors] = transformValidate(ruleAlert, null);
expect(validated).toEqual(null);
expect(errors).toEqual('Invalid value "undefined" supplied to "name"');
});
@ -89,26 +86,16 @@ describe.each([
describe('transformValidateBulkError', () => {
test('it should do a validation correctly of a rule id', () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const validatedOrError = transformValidateBulkError(
'rule-1',
ruleAlert,
null,
isRuleRegistryEnabled
);
const ruleAlert = getRuleMock(getQueryRuleParams());
const validatedOrError = transformValidateBulkError('rule-1', ruleAlert, null);
expect(validatedOrError).toEqual(ruleOutput());
});
test('it should do an in-validation correctly of a rule id', () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
// @ts-expect-error
delete ruleAlert.name;
const validatedOrError = transformValidateBulkError(
'rule-1',
ruleAlert,
null,
isRuleRegistryEnabled
);
const validatedOrError = transformValidateBulkError('rule-1', ruleAlert, null);
const expected: BulkError = {
error: {
message: 'Invalid value "undefined" supplied to "name"',
@ -120,14 +107,9 @@ describe.each([
});
test('it should do a validation correctly of a rule id with rule execution summary passed in', () => {
const rule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const rule = getRuleMock(getQueryRuleParams());
const ruleExecutionSumary = getRuleExecutionSummarySucceeded();
const validatedOrError = transformValidateBulkError(
'rule-1',
rule,
ruleExecutionSumary,
isRuleRegistryEnabled
);
const validatedOrError = transformValidateBulkError('rule-1', rule, ruleExecutionSumary);
const expected: RulesSchema = {
...ruleOutput(),
execution_summary: ruleExecutionSumary,
@ -136,15 +118,10 @@ describe.each([
});
test('it should return error object if "alert" is not expected alert type', () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const ruleAlert = getRuleMock(getQueryRuleParams());
// @ts-expect-error
delete ruleAlert.alertTypeId;
const validatedOrError = transformValidateBulkError(
'rule-1',
ruleAlert,
null,
isRuleRegistryEnabled
);
const validatedOrError = transformValidateBulkError('rule-1', ruleAlert, null);
const expected: BulkError = {
error: {
message: 'Internal error transforming',

View file

@ -28,15 +28,9 @@ import { internalRuleToAPIResponse } from '../../schemas/rule_converters';
export const transformValidate = (
rule: PartialRule<RuleParams>,
ruleExecutionSummary: RuleExecutionSummary | null,
isRuleRegistryEnabled?: boolean,
legacyRuleActions?: LegacyRulesActionsSavedObject | null
): [RulesSchema | null, string | null] => {
const transformed = transform(
rule,
ruleExecutionSummary,
isRuleRegistryEnabled,
legacyRuleActions
);
const transformed = transform(rule, ruleExecutionSummary, legacyRuleActions);
if (transformed == null) {
return [null, 'Internal error transforming'];
} else {
@ -47,15 +41,9 @@ export const transformValidate = (
export const newTransformValidate = (
rule: PartialRule<RuleParams>,
ruleExecutionSummary: RuleExecutionSummary | null,
isRuleRegistryEnabled?: boolean,
legacyRuleActions?: LegacyRulesActionsSavedObject | null
): [FullResponseSchema | null, string | null] => {
const transformed = transform(
rule,
ruleExecutionSummary,
isRuleRegistryEnabled,
legacyRuleActions
);
const transformed = transform(rule, ruleExecutionSummary, legacyRuleActions);
if (transformed == null) {
return [null, 'Internal error transforming'];
} else {
@ -66,10 +54,9 @@ export const newTransformValidate = (
export const transformValidateBulkError = (
ruleId: string,
rule: PartialRule<RuleParams>,
ruleExecutionSummary: RuleExecutionSummary | null,
isRuleRegistryEnabled?: boolean
ruleExecutionSummary: RuleExecutionSummary | null
): RulesSchema | BulkError => {
if (isAlertType(isRuleRegistryEnabled ?? false, rule)) {
if (isAlertType(rule)) {
const transformed = internalRuleToAPIResponse(rule, ruleExecutionSummary);
const [validated, errors] = validateNonExact(transformed, rulesSchema);
if (errors != null || validated == null) {

View file

@ -12,10 +12,7 @@ import { buildSiemResponse } from '../utils';
import { readTags } from '../../tags/read_tags';
export const readTagsRoute = (
router: SecuritySolutionPluginRouter,
isRuleRegistryEnabled: boolean
) => {
export const readTagsRoute = (router: SecuritySolutionPluginRouter) => {
router.get(
{
path: DETECTION_ENGINE_TAGS_URL,
@ -34,7 +31,6 @@ export const readTagsRoute = (
try {
const tags = await readTags({
isRuleRegistryEnabled,
rulesClient,
});
return response.ok({ body: tags });

View file

@ -10,10 +10,7 @@ import { transformBulkError, BulkError, convertToSnakeCase, SiemResponseFactory
import { responseMock } from './__mocks__';
import { CustomHttpRequestError } from '../../../utils/custom_http_request_error';
describe.each([
['Legacy', false],
['RAC', true],
])('utils - %s', (_, isRuleRegistryEnabled) => {
describe('utils', () => {
describe('transformBulkError', () => {
test('returns transformed object if it is a custom error object', () => {
const customError = new CustomHttpRequestError('some custom error message', 400);

View file

@ -8,8 +8,7 @@
import { CreateRulesOptions } from './types';
import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks';
export const getCreateRulesOptionsMock = (isRuleRegistryEnabled: boolean): CreateRulesOptions => ({
isRuleRegistryEnabled,
export const getCreateRulesOptionsMock = (): CreateRulesOptions => ({
author: ['Elastic'],
buildingBlockType: undefined,
rulesClient: rulesClientMock.create(),
@ -62,10 +61,7 @@ export const getCreateRulesOptionsMock = (isRuleRegistryEnabled: boolean): Creat
actions: [],
});
export const getCreateMlRulesOptionsMock = (
isRuleRegistryEnabled: boolean
): CreateRulesOptions => ({
isRuleRegistryEnabled,
export const getCreateMlRulesOptionsMock = (): CreateRulesOptions => ({
author: ['Elastic'],
buildingBlockType: undefined,
rulesClient: rulesClientMock.create(),
@ -118,9 +114,7 @@ export const getCreateMlRulesOptionsMock = (
actions: [],
});
export const getCreateThreatMatchRulesOptionsMock = (
isRuleRegistryEnabled: boolean
): CreateRulesOptions => ({
export const getCreateThreatMatchRulesOptionsMock = (): CreateRulesOptions => ({
actions: [],
anomalyThreshold: undefined,
author: ['Elastic'],
@ -136,7 +130,6 @@ export const getCreateThreatMatchRulesOptionsMock = (
immutable: false,
index: ['*'],
interval: '5m',
isRuleRegistryEnabled,
itemsPerSearch: undefined,
language: 'kuery',
license: 'Elastic License',

View file

@ -12,12 +12,9 @@ import {
} from './create_rules.mock';
import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../common/constants';
describe.each([
['Legacy', false],
['RAC', true],
])('createRules - %s', (_, isRuleRegistryEnabled) => {
describe('createRules', () => {
it('calls the rulesClient with legacy ML params', async () => {
const ruleOptions = getCreateMlRulesOptionsMock(isRuleRegistryEnabled);
const ruleOptions = getCreateMlRulesOptionsMock();
await createRules(ruleOptions);
expect(ruleOptions.rulesClient.create).toHaveBeenCalledWith(
expect.objectContaining({
@ -33,7 +30,7 @@ describe.each([
it('calls the rulesClient with ML params', async () => {
const ruleOptions = {
...getCreateMlRulesOptionsMock(isRuleRegistryEnabled),
...getCreateMlRulesOptionsMock(),
machineLearningJobId: ['new_job_1', 'new_job_2'],
};
await createRules(ruleOptions);
@ -50,7 +47,7 @@ describe.each([
});
it('populates a threatIndicatorPath value for threat_match rule if empty', async () => {
const ruleOptions = getCreateThreatMatchRulesOptionsMock(isRuleRegistryEnabled);
const ruleOptions = getCreateThreatMatchRulesOptionsMock();
delete ruleOptions.threatIndicatorPath;
await createRules(ruleOptions);
expect(ruleOptions.rulesClient.create).toHaveBeenCalledWith(
@ -65,7 +62,7 @@ describe.each([
});
it('does not populate a threatIndicatorPath value for other rules if empty', async () => {
const ruleOptions = getCreateMlRulesOptionsMock(isRuleRegistryEnabled);
const ruleOptions = getCreateMlRulesOptionsMock();
delete ruleOptions.threatIndicatorPath;
await createRules(ruleOptions);
expect(ruleOptions.rulesClient.create).not.toHaveBeenCalledWith(

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { SIGNALS_ID, ruleTypeMappings } from '@kbn/securitysolution-rules';
import { ruleTypeMappings } from '@kbn/securitysolution-rules';
import { RuleTypeParams, SanitizedRule } from '@kbn/alerting-plugin/common';
import {
@ -75,7 +75,6 @@ export const createRules = async ({
version,
exceptionsList,
actions,
isRuleRegistryEnabled,
id,
}: CreateRulesOptions): Promise<SanitizedRule<RuleTypeParams>> => {
const rule = await rulesClient.create<RuleTypeParams>({
@ -85,7 +84,7 @@ export const createRules = async ({
data: {
name,
tags: addTags(tags, ruleId, immutable),
alertTypeId: isRuleRegistryEnabled ? ruleTypeMappings[type] : SIGNALS_ID,
alertTypeId: ruleTypeMappings[type],
consumer: SERVER_APP_ID,
params: {
anomalyThreshold,

View file

@ -18,73 +18,70 @@ describe('duplicateRule', () => {
(uuid.v4 as jest.Mock).mockReturnValue('newId');
expect(
duplicateRule(
{
id: 'oldTestRuleId',
notifyWhen: 'onActiveAlert',
name: 'test',
tags: ['test', '__internal_rule_id:oldTestRuleId', `${INTERNAL_IMMUTABLE_KEY}:false`],
alertTypeId: 'siem.signals',
consumer: 'siem',
params: {
savedId: undefined,
author: [],
description: 'test',
ruleId: 'oldTestRuleId',
falsePositives: [],
from: 'now-360s',
immutable: false,
license: '',
outputIndex: '.siem-signals-default',
meta: undefined,
maxSignals: 100,
riskScore: 42,
riskScoreMapping: [],
severity: 'low',
severityMapping: [],
threat: [],
to: 'now',
references: [],
version: 1,
exceptionsList: [],
type: 'query',
language: 'kuery',
index: [],
query: 'process.args : "chmod"',
filters: [],
buildingBlockType: undefined,
namespace: undefined,
note: undefined,
timelineId: undefined,
timelineTitle: undefined,
ruleNameOverride: undefined,
timestampOverride: undefined,
},
schedule: {
interval: '5m',
},
enabled: false,
actions: [],
throttle: null,
apiKeyOwner: 'kibana',
createdBy: 'kibana',
updatedBy: 'kibana',
muteAll: false,
mutedInstanceIds: [],
updatedAt: new Date(2021, 0),
createdAt: new Date(2021, 0),
scheduledTaskId: undefined,
executionStatus: {
lastExecutionDate: new Date(2021, 0),
status: 'ok',
},
duplicateRule({
id: 'oldTestRuleId',
notifyWhen: 'onActiveAlert',
name: 'test',
tags: ['test', '__internal_rule_id:oldTestRuleId', `${INTERNAL_IMMUTABLE_KEY}:false`],
alertTypeId: 'siem.signals',
consumer: 'siem',
params: {
savedId: undefined,
author: [],
description: 'test',
ruleId: 'oldTestRuleId',
falsePositives: [],
from: 'now-360s',
immutable: false,
license: '',
outputIndex: '.siem-signals-default',
meta: undefined,
maxSignals: 100,
riskScore: 42,
riskScoreMapping: [],
severity: 'low',
severityMapping: [],
threat: [],
to: 'now',
references: [],
version: 1,
exceptionsList: [],
type: 'query',
language: 'kuery',
index: [],
query: 'process.args : "chmod"',
filters: [],
buildingBlockType: undefined,
namespace: undefined,
note: undefined,
timelineId: undefined,
timelineTitle: undefined,
ruleNameOverride: undefined,
timestampOverride: undefined,
},
false
)
schedule: {
interval: '5m',
},
enabled: false,
actions: [],
throttle: null,
apiKeyOwner: 'kibana',
createdBy: 'kibana',
updatedBy: 'kibana',
muteAll: false,
mutedInstanceIds: [],
updatedAt: new Date(2021, 0),
createdAt: new Date(2021, 0),
scheduledTaskId: undefined,
executionStatus: {
lastExecutionDate: new Date(2021, 0),
status: 'ok',
},
})
).toMatchInlineSnapshot(`
Object {
"actions": Array [],
"alertTypeId": "siem.signals",
"alertTypeId": "siem.queryRule",
"consumer": "siem",
"enabled": false,
"name": "test [Duplicate]",

View file

@ -8,7 +8,7 @@
import uuid from 'uuid';
import { i18n } from '@kbn/i18n';
import { ruleTypeMappings, SIGNALS_ID } from '@kbn/securitysolution-rules';
import { ruleTypeMappings } from '@kbn/securitysolution-rules';
import { SanitizedRule } from '@kbn/alerting-plugin/common';
import { SERVER_APP_ID } from '../../../../common/constants';
@ -22,15 +22,12 @@ const DUPLICATE_TITLE = i18n.translate(
}
);
export const duplicateRule = (
rule: SanitizedRule<RuleParams>,
isRuleRegistryEnabled: boolean
): InternalRuleCreate => {
export const duplicateRule = (rule: SanitizedRule<RuleParams>): InternalRuleCreate => {
const newRuleId = uuid.v4();
return {
name: `${rule.name} [${DUPLICATE_TITLE}]`,
tags: addTags(rule.tags, newRuleId, false),
alertTypeId: isRuleRegistryEnabled ? ruleTypeMappings[rule.params.type] : SIGNALS_ID,
alertTypeId: ruleTypeMappings[rule.params.type],
consumer: SERVER_APP_ID,
params: {
...rule.params,

View file

@ -12,7 +12,6 @@ import {
QUERY_RULE_TYPE_ID,
SAVED_QUERY_RULE_TYPE_ID,
THRESHOLD_RULE_TYPE_ID,
SIGNALS_ID,
} from '@kbn/securitysolution-rules';
import { getFilter } from './find_rules';
@ -25,26 +24,13 @@ const allAlertTypeIds = `(alert.attributes.alertTypeId: ${EQL_RULE_TYPE_ID}
OR alert.attributes.alertTypeId: ${THRESHOLD_RULE_TYPE_ID})`.replace(/[\n\r]/g, '');
describe('find_rules', () => {
const fullFilterTestCases: Array<[boolean, string]> = [
[false, `alert.attributes.alertTypeId: ${SIGNALS_ID} AND alert.attributes.enabled: true`],
[true, `${allAlertTypeIds} AND alert.attributes.enabled: true`],
];
const nullFilterTestCases: Array<[boolean, string]> = [
[false, `alert.attributes.alertTypeId: ${SIGNALS_ID}`],
[true, allAlertTypeIds],
];
test('it returns a full filter with an AND if sent down', () => {
expect(getFilter('alert.attributes.enabled: true')).toEqual(
`${allAlertTypeIds} AND alert.attributes.enabled: true`
);
});
test.each(fullFilterTestCases)(
'it returns a full filter with an AND if sent down [rule registry enabled: %p]',
(isRuleRegistryEnabled, expected) => {
expect(getFilter('alert.attributes.enabled: true', isRuleRegistryEnabled)).toEqual(expected);
}
);
test.each(nullFilterTestCases)(
'it returns existing filter with no AND when not set [rule registry enabled: %p]',
(isRuleRegistryEnabled, expected) => {
expect(getFilter(null, isRuleRegistryEnabled)).toEqual(expected);
}
);
test('it returns existing filter with no AND when not set [rule registry enabled: %p]', () => {
expect(getFilter(null)).toEqual(allAlertTypeIds);
});
});

View file

@ -5,22 +5,17 @@
* 2.0.
*/
import { SIGNALS_ID, ruleTypeMappings } from '@kbn/securitysolution-rules';
import { ruleTypeMappings } from '@kbn/securitysolution-rules';
import { FindResult } from '@kbn/alerting-plugin/server';
import { RuleParams } from '../schemas/rule_schemas';
import { FindRuleOptions } from './types';
export const getFilter = (
filter: string | null | undefined,
isRuleRegistryEnabled: boolean = false
) => {
const alertTypeFilter = isRuleRegistryEnabled
? `(${Object.values(ruleTypeMappings)
.map((type) => `alert.attributes.alertTypeId: ${type}`)
.filter((type, i, arr) => type != null && arr.indexOf(type) === i)
.join(' OR ')})`
: `alert.attributes.alertTypeId: ${SIGNALS_ID}`;
export const getFilter = (filter: string | null | undefined) => {
const alertTypeFilter = `(${Object.values(ruleTypeMappings)
.map((type) => `alert.attributes.alertTypeId: ${type}`)
.filter((type, i, arr) => type != null && arr.indexOf(type) === i)
.join(' OR ')})`;
if (filter == null) {
return alertTypeFilter;
} else {
@ -36,14 +31,13 @@ export const findRules = ({
filter,
sortField,
sortOrder,
isRuleRegistryEnabled,
}: FindRuleOptions): Promise<FindResult<RuleParams>> => {
return rulesClient.find({
options: {
fields,
page,
perPage,
filter: getFilter(filter, isRuleRegistryEnabled),
filter: getFilter(filter),
sortOrder,
sortField,
},

View file

@ -7,7 +7,7 @@
import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks';
import {
getAlertMock,
getRuleMock,
getFindResultWithSingleHit,
getFindResultWithMultiHits,
} from '../routes/__mocks__/request_responses';
@ -20,10 +20,7 @@ import {
getNonPackagedRulesCount,
} from './get_existing_prepackaged_rules';
describe.each([
['Legacy', false],
['RAC', true],
])('get_existing_prepackaged_rules - %s', (_, isRuleRegistryEnabled) => {
describe('get_existing_prepackaged_rules', () => {
afterEach(() => {
jest.resetAllMocks();
});
@ -31,23 +28,23 @@ describe.each([
describe('getExistingPrepackagedRules', () => {
test('should return a single item in a single page', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
const rules = await getExistingPrepackagedRules({ isRuleRegistryEnabled, rulesClient });
expect(rules).toEqual([getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())]);
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const rules = await getExistingPrepackagedRules({ rulesClient });
expect(rules).toEqual([getRuleMock(getQueryRuleParams())]);
});
test('should return 3 items over 1 page with all on one page', async () => {
const rulesClient = rulesClientMock.create();
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.params.immutable = true;
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.params.immutable = true;
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
const result3 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result3 = getRuleMock(getQueryRuleParams());
result3.params.immutable = true;
result3.id = 'f3e1bf0b-b95f-43da-b1de-5d2f0af2287a';
@ -71,7 +68,7 @@ describe.each([
})
);
const rules = await getExistingPrepackagedRules({ isRuleRegistryEnabled, rulesClient });
const rules = await getExistingPrepackagedRules({ rulesClient });
expect(rules).toEqual([result1, result2, result3]);
});
});
@ -79,18 +76,18 @@ describe.each([
describe('getNonPackagedRules', () => {
test('should return a single item in a single page', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
const rules = await getNonPackagedRules({ isRuleRegistryEnabled, rulesClient });
expect(rules).toEqual([getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())]);
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const rules = await getNonPackagedRules({ rulesClient });
expect(rules).toEqual([getRuleMock(getQueryRuleParams())]);
});
test('should return 2 items over 1 page', async () => {
const rulesClient = rulesClientMock.create();
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
// first result mock which is for returning the total
@ -108,20 +105,20 @@ describe.each([
getFindResultWithMultiHits({ data: [result1, result2], perPage: 2, page: 1, total: 2 })
);
const rules = await getNonPackagedRules({ isRuleRegistryEnabled, rulesClient });
const rules = await getNonPackagedRules({ rulesClient });
expect(rules).toEqual([result1, result2]);
});
test('should return 3 items over 1 page with all on one page', async () => {
const rulesClient = rulesClientMock.create();
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
const result3 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result3 = getRuleMock(getQueryRuleParams());
result3.id = 'f3e1bf0b-b95f-43da-b1de-5d2f0af2287a';
// first result mock which is for returning the total
@ -144,7 +141,7 @@ describe.each([
})
);
const rules = await getNonPackagedRules({ isRuleRegistryEnabled, rulesClient });
const rules = await getNonPackagedRules({ rulesClient });
expect(rules).toEqual([result1, result2, result3]);
});
});
@ -152,18 +149,18 @@ describe.each([
describe('getRules', () => {
test('should return a single item in a single page', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
const rules = await getRules({ isRuleRegistryEnabled, rulesClient, filter: '' });
expect(rules).toEqual([getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())]);
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const rules = await getRules({ rulesClient, filter: '' });
expect(rules).toEqual([getRuleMock(getQueryRuleParams())]);
});
test('should return 2 items over two pages, one per page', async () => {
const rulesClient = rulesClientMock.create();
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
// first result mock which is for returning the total
@ -181,7 +178,7 @@ describe.each([
getFindResultWithMultiHits({ data: [result1, result2], perPage: 2, page: 1, total: 2 })
);
const rules = await getRules({ isRuleRegistryEnabled, rulesClient, filter: '' });
const rules = await getRules({ rulesClient, filter: '' });
expect(rules).toEqual([result1, result2]);
});
});
@ -189,8 +186,8 @@ describe.each([
describe('getRulesCount', () => {
test('it returns a count', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
const rules = await getRulesCount({ isRuleRegistryEnabled, rulesClient, filter: '' });
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const rules = await getRulesCount({ rulesClient, filter: '' });
expect(rules).toEqual(1);
});
});
@ -198,8 +195,8 @@ describe.each([
describe('getNonPackagedRulesCount', () => {
test('it returns a count', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
const rules = await getNonPackagedRulesCount({ isRuleRegistryEnabled, rulesClient });
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const rules = await getNonPackagedRulesCount({ rulesClient });
expect(rules).toEqual(1);
});
});

View file

@ -14,26 +14,21 @@ export const FILTER_NON_PREPACKED_RULES = `alert.attributes.tags: "${INTERNAL_IM
export const FILTER_PREPACKED_RULES = `alert.attributes.tags: "${INTERNAL_IMMUTABLE_KEY}:true"`;
export const getNonPackagedRulesCount = async ({
isRuleRegistryEnabled,
rulesClient,
}: {
isRuleRegistryEnabled: boolean;
rulesClient: RulesClient;
}): Promise<number> => {
return getRulesCount({ isRuleRegistryEnabled, rulesClient, filter: FILTER_NON_PREPACKED_RULES });
return getRulesCount({ rulesClient, filter: FILTER_NON_PREPACKED_RULES });
};
export const getRulesCount = async ({
rulesClient,
filter,
isRuleRegistryEnabled,
}: {
rulesClient: RulesClient;
filter: string;
isRuleRegistryEnabled: boolean;
}): Promise<number> => {
const firstRule = await findRules({
isRuleRegistryEnabled,
rulesClient,
filter,
perPage: 1,
@ -48,15 +43,12 @@ export const getRulesCount = async ({
export const getRules = async ({
rulesClient,
filter,
isRuleRegistryEnabled,
}: {
rulesClient: RulesClient;
filter: string;
isRuleRegistryEnabled: boolean;
}) => {
const count = await getRulesCount({ rulesClient, filter, isRuleRegistryEnabled });
const count = await getRulesCount({ rulesClient, filter });
const rules = await findRules({
isRuleRegistryEnabled,
rulesClient,
filter,
perPage: count,
@ -66,7 +58,7 @@ export const getRules = async ({
fields: undefined,
});
if (isAlertTypes(isRuleRegistryEnabled, rules.data)) {
if (isAlertTypes(rules.data)) {
return rules.data;
} else {
// If this was ever true, you have a really messed up system.
@ -77,28 +69,22 @@ export const getRules = async ({
export const getNonPackagedRules = async ({
rulesClient,
isRuleRegistryEnabled,
}: {
rulesClient: RulesClient;
isRuleRegistryEnabled: boolean;
}): Promise<RuleAlertType[]> => {
return getRules({
rulesClient,
filter: FILTER_NON_PREPACKED_RULES,
isRuleRegistryEnabled,
});
};
export const getExistingPrepackagedRules = async ({
rulesClient,
isRuleRegistryEnabled,
}: {
rulesClient: RulesClient;
isRuleRegistryEnabled: boolean;
}): Promise<RuleAlertType[]> => {
return getRules({
rulesClient,
filter: FILTER_PREPACKED_RULES,
isRuleRegistryEnabled,
});
};

View file

@ -6,7 +6,7 @@
*/
import {
getAlertMock,
getRuleMock,
getFindResultWithSingleHit,
FindHit,
getEmptySavedObjectsResponse,
@ -27,10 +27,7 @@ import { requestContextMock } from '../routes/__mocks__/request_context';
const exceptionsClient = getExceptionListClientMock();
describe.each([
['Legacy', false],
['RAC', true],
])('getExportAll - %s', (_, isRuleRegistryEnabled) => {
describe('getExportAll', () => {
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
const { clients } = requestContextMock.createTools();
@ -40,8 +37,8 @@ describe.each([
test('it exports everything from the alerts client', async () => {
const rulesClient = rulesClientMock.create();
const result = getFindResultWithSingleHit(isRuleRegistryEnabled);
const alert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result = getFindResultWithSingleHit();
const alert = getRuleMock(getQueryRuleParams());
alert.params = {
...alert.params,
@ -58,8 +55,7 @@ describe.each([
rulesClient,
exceptionsClient,
clients.savedObjectsClient,
logger,
isRuleRegistryEnabled
logger
);
const rulesJson = JSON.parse(exports.rulesNdjson);
const detailsJson = JSON.parse(exports.exportDetails);
@ -134,8 +130,7 @@ describe.each([
rulesClient,
exceptionsClient,
clients.savedObjectsClient,
logger,
isRuleRegistryEnabled
logger
);
expect(exports).toEqual({
rulesNdjson: '',

View file

@ -22,14 +22,13 @@ export const getExportAll = async (
rulesClient: RulesClient,
exceptionsClient: ExceptionListClient | undefined,
savedObjectsClient: RuleExecutorServices['savedObjectsClient'],
logger: Logger,
isRuleRegistryEnabled: boolean
logger: Logger
): Promise<{
rulesNdjson: string;
exportDetails: string;
exceptionLists: string | null;
}> => {
const ruleAlertTypes = await getNonPackagedRules({ rulesClient, isRuleRegistryEnabled });
const ruleAlertTypes = await getNonPackagedRules({ rulesClient });
const alertIds = ruleAlertTypes.map((rule) => rule.id);
// Gather actions

View file

@ -7,7 +7,7 @@
import { getExportByObjectIds, getRulesFromObjects, RulesErrors } from './get_export_by_object_ids';
import {
getAlertMock,
getRuleMock,
getFindResultWithSingleHit,
FindHit,
getEmptySavedObjectsResponse,
@ -26,10 +26,7 @@ const exceptionsClient = getExceptionListClientMock();
import { loggingSystemMock } from '@kbn/core/server/mocks';
import { requestContextMock } from '../routes/__mocks__/request_context';
describe.each([
['Legacy', false],
['RAC', true],
])('get_export_by_object_ids - %s', (_, isRuleRegistryEnabled) => {
describe('get_export_by_object_ids', () => {
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
const { clients } = requestContextMock.createTools();
@ -44,7 +41,7 @@ describe.each([
describe('getExportByObjectIds', () => {
test('it exports object ids into an expected string with new line characters', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const objects = [{ rule_id: 'rule-1' }];
const exports = await getExportByObjectIds(
@ -52,8 +49,7 @@ describe.each([
exceptionsClient,
clients.savedObjectsClient,
objects,
logger,
isRuleRegistryEnabled
logger
);
const exportsObj = {
rulesNdjson: JSON.parse(exports.rulesNdjson),
@ -118,7 +114,7 @@ describe.each([
test('it does not export immutable rules', async () => {
const rulesClient = rulesClientMock.create();
const result = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result = getRuleMock(getQueryRuleParams());
result.params.immutable = true;
const findResult: FindHit = {
@ -128,7 +124,7 @@ describe.each([
data: [result],
};
rulesClient.get.mockResolvedValue(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
rulesClient.get.mockResolvedValue(getRuleMock(getQueryRuleParams()));
rulesClient.find.mockResolvedValue(findResult);
const objects = [{ rule_id: 'rule-1' }];
@ -137,8 +133,7 @@ describe.each([
exceptionsClient,
clients.savedObjectsClient,
objects,
logger,
isRuleRegistryEnabled
logger
);
const details = getOutputDetailsSampleWithExceptions({
missingRules: [{ rule_id: 'rule-1' }],
@ -155,15 +150,14 @@ describe.each([
describe('getRulesFromObjects', () => {
test('it returns transformed rules from objects sent in', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const objects = [{ rule_id: 'rule-1' }];
const exports = await getRulesFromObjects(
rulesClient,
clients.savedObjectsClient,
objects,
logger,
isRuleRegistryEnabled
logger
);
const expected: RulesErrors = {
exportedCount: 1,
@ -220,7 +214,7 @@ describe.each([
test('it does not transform the rule if the rule is an immutable rule and designates it as a missing rule', async () => {
const rulesClient = rulesClientMock.create();
const result = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result = getRuleMock(getQueryRuleParams());
result.params.immutable = true;
const findResult: FindHit = {
@ -238,8 +232,7 @@ describe.each([
rulesClient,
clients.savedObjectsClient,
objects,
logger,
isRuleRegistryEnabled
logger
);
const expected: RulesErrors = {
exportedCount: 0,
@ -267,8 +260,7 @@ describe.each([
rulesClient,
clients.savedObjectsClient,
objects,
logger,
isRuleRegistryEnabled
logger
);
const expected: RulesErrors = {
exportedCount: 0,

View file

@ -45,8 +45,7 @@ export const getExportByObjectIds = async (
exceptionsClient: ExceptionListClient | undefined,
savedObjectsClient: RuleExecutorServices['savedObjectsClient'],
objects: Array<{ rule_id: string }>,
logger: Logger,
isRuleRegistryEnabled: boolean
logger: Logger
): Promise<{
rulesNdjson: string;
exportDetails: string;
@ -56,8 +55,7 @@ export const getExportByObjectIds = async (
rulesClient,
savedObjectsClient,
objects,
logger,
isRuleRegistryEnabled
logger
);
// Retrieve exceptions
@ -83,8 +81,7 @@ export const getRulesFromObjects = async (
rulesClient: RulesClient,
savedObjectsClient: RuleExecutorServices['savedObjectsClient'],
objects: Array<{ rule_id: string }>,
logger: Logger,
isRuleRegistryEnabled: boolean
logger: Logger
): Promise<RulesErrors> => {
// If we put more than 1024 ids in one block like "alert.attributes.tags: (id1 OR id2 OR ... OR id1100)"
// then the KQL -> ES DSL query generator still puts them all in the same "should" array, but ES defaults
@ -102,7 +99,6 @@ export const getRulesFromObjects = async (
})
.join(' OR ');
const rules = await findRules({
isRuleRegistryEnabled,
rulesClient,
filter,
page: 1,
@ -122,7 +118,7 @@ export const getRulesFromObjects = async (
const matchingRule = rules.data.find((rule) => rule.params.ruleId === ruleId);
if (
matchingRule != null &&
isAlertType(isRuleRegistryEnabled, matchingRule) &&
isAlertType(matchingRule) &&
matchingRule.params.immutable !== true
) {
return {

View file

@ -6,15 +6,12 @@
*/
import { getRulesToInstall } from './get_rules_to_install';
import { getAlertMock } from '../routes/__mocks__/request_responses';
import { getRuleMock } from '../routes/__mocks__/request_responses';
import { getAddPrepackagedRulesSchemaDecodedMock } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock';
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
import { AddPrepackagedRulesSchemaDecoded } from '../../../../common/detection_engine/schemas/request';
describe.each([
['Legacy', false],
['RAC', true],
])('get_rules_to_install - %s', (_, isRuleRegistryEnabled) => {
describe('get_rules_to_install', () => {
test('should return empty array if both rule sets are empty', () => {
const update = getRulesToInstall([], []);
expect(update).toEqual([]);
@ -25,7 +22,7 @@ describe.each([
getAddPrepackagedRulesSchemaDecodedMock() as AddPrepackagedRulesSchemaDecoded;
ruleFromFileSystem.rule_id = 'rule-1';
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
const update = getRulesToInstall([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([]);
@ -36,7 +33,7 @@ describe.each([
getAddPrepackagedRulesSchemaDecodedMock() as AddPrepackagedRulesSchemaDecoded;
ruleFromFileSystem.rule_id = 'rule-1';
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-2';
const update = getRulesToInstall([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([ruleFromFileSystem]);
@ -51,7 +48,7 @@ describe.each([
getAddPrepackagedRulesSchemaDecodedMock() as AddPrepackagedRulesSchemaDecoded;
ruleFromFileSystem2.rule_id = 'rule-2';
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-3';
const update = getRulesToInstall([ruleFromFileSystem1, ruleFromFileSystem2], [installedRule]);
expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]);
@ -70,7 +67,7 @@ describe.each([
getAddPrepackagedRulesSchemaDecodedMock() as AddPrepackagedRulesSchemaDecoded;
ruleFromFileSystem3.rule_id = 'rule-3';
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-3';
const update = getRulesToInstall(
[ruleFromFileSystem1, ruleFromFileSystem2, ruleFromFileSystem3],

View file

@ -6,473 +6,468 @@
*/
import { filterInstalledRules, getRulesToUpdate, mergeExceptionLists } from './get_rules_to_update';
import { getAlertMock } from '../routes/__mocks__/request_responses';
import { getRuleMock } from '../routes/__mocks__/request_responses';
import { getAddPrepackagedRulesSchemaDecodedMock } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock';
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
describe.each([
['Legacy', false],
['RAC', true],
])('get_rules_to_update - %s', (_, isRuleRegistryEnabled) => {
describe('get_rules_to_update', () => {
test('should return empty array if both rule sets are empty', () => {
const update = getRulesToUpdate([], []);
expect(update).toEqual([]);
});
test('should return empty array if the rule_id of the two rules do not match', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule.params.ruleId = 'rule-2';
installedRule.params.version = 1;
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([]);
});
test('should return empty array if the version of file system rule is less than the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 1;
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 2;
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([]);
});
test('should return empty array if the version of file system rule is the same as the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 1;
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 1;
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([]);
});
test('should return the rule to update if the version of file system rule is greater than the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 1;
installedRule.params.exceptionsList = [];
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([ruleFromFileSystem]);
});
test('should return 1 rule out of 2 to update if the version of file system rule is greater than the installed version of just one', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [];
const installedRule2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule2.params.ruleId = 'rule-2';
installedRule2.params.version = 1;
installedRule2.params.exceptionsList = [];
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule1, installedRule2]);
expect(update).toEqual([ruleFromFileSystem]);
});
test('should return 2 rules out of 2 to update if the version of file system rule is greater than the installed version of both', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem2.rule_id = 'rule-2';
ruleFromFileSystem2.version = 2;
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [];
const installedRule2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule2.params.ruleId = 'rule-2';
installedRule2.params.version = 1;
installedRule2.params.exceptionsList = [];
const update = getRulesToUpdate(
[ruleFromFileSystem1, ruleFromFileSystem2],
[installedRule1, installedRule2]
);
expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]);
});
test('should add back an exception_list if it was removed by the end user on an immutable rule during an upgrade', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [];
const [update] = getRulesToUpdate([ruleFromFileSystem1], [installedRule1]);
expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list);
});
test('should not remove an additional exception_list if an additional one was added by the end user on an immutable rule during an upgrade', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'second_exception_list',
list_id: 'some-other-id',
namespace_type: 'single',
type: 'detection',
},
];
const [update] = getRulesToUpdate([ruleFromFileSystem1], [installedRule1]);
expect(update.exceptions_list).toEqual([
...ruleFromFileSystem1.exceptions_list,
...installedRule1.params.exceptionsList,
]);
});
test('should not remove an existing exception_list if they are the same between the current installed one and the upgraded one', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const [update] = getRulesToUpdate([ruleFromFileSystem1], [installedRule1]);
expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list);
});
test('should not remove an existing exception_list if the rule has an empty exceptions list', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const [update] = getRulesToUpdate([ruleFromFileSystem1], [installedRule1]);
expect(update.exceptions_list).toEqual(installedRule1.params.exceptionsList);
});
test('should not remove an existing exception_list if the rule has an empty exceptions list for multiple rules', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem2.exceptions_list = [];
ruleFromFileSystem2.rule_id = 'rule-2';
ruleFromFileSystem2.version = 2;
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const installedRule2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule2.params.ruleId = 'rule-2';
installedRule2.params.version = 1;
installedRule2.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const [update1, update2] = getRulesToUpdate(
[ruleFromFileSystem1, ruleFromFileSystem2],
[installedRule1, installedRule2]
);
expect(update1.exceptions_list).toEqual(installedRule1.params.exceptionsList);
expect(update2.exceptions_list).toEqual(installedRule2.params.exceptionsList);
});
test('should not remove an existing exception_list if the rule has an empty exceptions list for mixed rules', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem2.exceptions_list = [];
ruleFromFileSystem2.rule_id = 'rule-2';
ruleFromFileSystem2.version = 2;
ruleFromFileSystem2.exceptions_list = [
{
id: 'second_list',
list_id: 'second_list',
namespace_type: 'single',
type: 'detection',
},
];
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const installedRule2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule2.params.ruleId = 'rule-2';
installedRule2.params.version = 1;
installedRule2.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const [update1, update2] = getRulesToUpdate(
[ruleFromFileSystem1, ruleFromFileSystem2],
[installedRule1, installedRule2]
);
expect(update1.exceptions_list).toEqual(installedRule1.params.exceptionsList);
expect(update2.exceptions_list).toEqual([
...ruleFromFileSystem2.exceptions_list,
...installedRule2.params.exceptionsList,
]);
});
describe('get_rules_to_update', () => {
test('should return empty array if both rule sets are empty', () => {
const update = getRulesToUpdate([], []);
expect(update).toEqual([]);
});
describe('filterInstalledRules', () => {
test('should return "false" if the id of the two rules do not match', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
test('should return empty array if the rule_id of the two rules do not match', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule.params.ruleId = 'rule-2';
installedRule.params.version = 1;
const shouldUpdate = filterInstalledRules(ruleFromFileSystem, [installedRule]);
expect(shouldUpdate).toEqual(false);
});
test('should return "false" if the version of file system rule is less than the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 1;
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 2;
const shouldUpdate = filterInstalledRules(ruleFromFileSystem, [installedRule]);
expect(shouldUpdate).toEqual(false);
});
test('should return "false" if the version of file system rule is the same as the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 1;
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 1;
const shouldUpdate = filterInstalledRules(ruleFromFileSystem, [installedRule]);
expect(shouldUpdate).toEqual(false);
});
test('should return "true" to update if the version of file system rule is greater than the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const installedRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 1;
installedRule.params.exceptionsList = [];
const shouldUpdate = filterInstalledRules(ruleFromFileSystem, [installedRule]);
expect(shouldUpdate).toEqual(true);
});
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-2';
installedRule.params.version = 1;
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([]);
});
describe('mergeExceptionLists', () => {
test('should add back an exception_list if it was removed by the end user on an immutable rule during an upgrade', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
test('should return empty array if the version of file system rule is less than the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 1;
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [];
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 2;
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([]);
});
const update = mergeExceptionLists(ruleFromFileSystem1, [installedRule1]);
expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list);
});
test('should return empty array if the version of file system rule is the same as the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 1;
test('should not remove an additional exception_list if an additional one was added by the end user on an immutable rule during an upgrade', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 1;
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([]);
});
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'second_exception_list',
list_id: 'some-other-id',
namespace_type: 'single',
type: 'detection',
},
];
test('should return the rule to update if the version of file system rule is greater than the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const update = mergeExceptionLists(ruleFromFileSystem1, [installedRule1]);
expect(update.exceptions_list).toEqual([
...ruleFromFileSystem1.exceptions_list,
...installedRule1.params.exceptionsList,
]);
});
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 1;
installedRule.params.exceptionsList = [];
test('should not remove an existing exception_list if they are the same between the current installed one and the upgraded one', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]);
expect(update).toEqual([ruleFromFileSystem]);
});
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
test('should return 1 rule out of 2 to update if the version of file system rule is greater than the installed version of just one', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const update = mergeExceptionLists(ruleFromFileSystem1, [installedRule1]);
expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list);
});
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [];
test('should not remove an existing exception_list if the rule has an empty exceptions list', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule2 = getRuleMock(getQueryRuleParams());
installedRule2.params.ruleId = 'rule-2';
installedRule2.params.version = 1;
installedRule2.params.exceptionsList = [];
const installedRule1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const update = getRulesToUpdate([ruleFromFileSystem], [installedRule1, installedRule2]);
expect(update).toEqual([ruleFromFileSystem]);
});
const update = mergeExceptionLists(ruleFromFileSystem1, [installedRule1]);
expect(update.exceptions_list).toEqual(installedRule1.params.exceptionsList);
});
test('should return 2 rules out of 2 to update if the version of file system rule is greater than the installed version of both', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem2.rule_id = 'rule-2';
ruleFromFileSystem2.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [];
const installedRule2 = getRuleMock(getQueryRuleParams());
installedRule2.params.ruleId = 'rule-2';
installedRule2.params.version = 1;
installedRule2.params.exceptionsList = [];
const update = getRulesToUpdate(
[ruleFromFileSystem1, ruleFromFileSystem2],
[installedRule1, installedRule2]
);
expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]);
});
test('should add back an exception_list if it was removed by the end user on an immutable rule during an upgrade', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [];
const [update] = getRulesToUpdate([ruleFromFileSystem1], [installedRule1]);
expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list);
});
test('should not remove an additional exception_list if an additional one was added by the end user on an immutable rule during an upgrade', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'second_exception_list',
list_id: 'some-other-id',
namespace_type: 'single',
type: 'detection',
},
];
const [update] = getRulesToUpdate([ruleFromFileSystem1], [installedRule1]);
expect(update.exceptions_list).toEqual([
...ruleFromFileSystem1.exceptions_list,
...installedRule1.params.exceptionsList,
]);
});
test('should not remove an existing exception_list if they are the same between the current installed one and the upgraded one', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const [update] = getRulesToUpdate([ruleFromFileSystem1], [installedRule1]);
expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list);
});
test('should not remove an existing exception_list if the rule has an empty exceptions list', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const [update] = getRulesToUpdate([ruleFromFileSystem1], [installedRule1]);
expect(update.exceptions_list).toEqual(installedRule1.params.exceptionsList);
});
test('should not remove an existing exception_list if the rule has an empty exceptions list for multiple rules', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem2.exceptions_list = [];
ruleFromFileSystem2.rule_id = 'rule-2';
ruleFromFileSystem2.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const installedRule2 = getRuleMock(getQueryRuleParams());
installedRule2.params.ruleId = 'rule-2';
installedRule2.params.version = 1;
installedRule2.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const [update1, update2] = getRulesToUpdate(
[ruleFromFileSystem1, ruleFromFileSystem2],
[installedRule1, installedRule2]
);
expect(update1.exceptions_list).toEqual(installedRule1.params.exceptionsList);
expect(update2.exceptions_list).toEqual(installedRule2.params.exceptionsList);
});
test('should not remove an existing exception_list if the rule has an empty exceptions list for mixed rules', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem2.exceptions_list = [];
ruleFromFileSystem2.rule_id = 'rule-2';
ruleFromFileSystem2.version = 2;
ruleFromFileSystem2.exceptions_list = [
{
id: 'second_list',
list_id: 'second_list',
namespace_type: 'single',
type: 'detection',
},
];
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const installedRule2 = getRuleMock(getQueryRuleParams());
installedRule2.params.ruleId = 'rule-2';
installedRule2.params.version = 1;
installedRule2.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const [update1, update2] = getRulesToUpdate(
[ruleFromFileSystem1, ruleFromFileSystem2],
[installedRule1, installedRule2]
);
expect(update1.exceptions_list).toEqual(installedRule1.params.exceptionsList);
expect(update2.exceptions_list).toEqual([
...ruleFromFileSystem2.exceptions_list,
...installedRule2.params.exceptionsList,
]);
});
});
describe('filterInstalledRules', () => {
test('should return "false" if the id of the two rules do not match', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-2';
installedRule.params.version = 1;
const shouldUpdate = filterInstalledRules(ruleFromFileSystem, [installedRule]);
expect(shouldUpdate).toEqual(false);
});
test('should return "false" if the version of file system rule is less than the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 1;
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 2;
const shouldUpdate = filterInstalledRules(ruleFromFileSystem, [installedRule]);
expect(shouldUpdate).toEqual(false);
});
test('should return "false" if the version of file system rule is the same as the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 1;
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 1;
const shouldUpdate = filterInstalledRules(ruleFromFileSystem, [installedRule]);
expect(shouldUpdate).toEqual(false);
});
test('should return "true" to update if the version of file system rule is greater than the installed version', () => {
const ruleFromFileSystem = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem.rule_id = 'rule-1';
ruleFromFileSystem.version = 2;
const installedRule = getRuleMock(getQueryRuleParams());
installedRule.params.ruleId = 'rule-1';
installedRule.params.version = 1;
installedRule.params.exceptionsList = [];
const shouldUpdate = filterInstalledRules(ruleFromFileSystem, [installedRule]);
expect(shouldUpdate).toEqual(true);
});
});
describe('mergeExceptionLists', () => {
test('should add back an exception_list if it was removed by the end user on an immutable rule during an upgrade', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [];
const update = mergeExceptionLists(ruleFromFileSystem1, [installedRule1]);
expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list);
});
test('should not remove an additional exception_list if an additional one was added by the end user on an immutable rule during an upgrade', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'second_exception_list',
list_id: 'some-other-id',
namespace_type: 'single',
type: 'detection',
},
];
const update = mergeExceptionLists(ruleFromFileSystem1, [installedRule1]);
expect(update.exceptions_list).toEqual([
...ruleFromFileSystem1.exceptions_list,
...installedRule1.params.exceptionsList,
]);
});
test('should not remove an existing exception_list if they are the same between the current installed one and the upgraded one', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const update = mergeExceptionLists(ruleFromFileSystem1, [installedRule1]);
expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list);
});
test('should not remove an existing exception_list if the rule has an empty exceptions list', () => {
const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaDecodedMock();
ruleFromFileSystem1.exceptions_list = [];
ruleFromFileSystem1.rule_id = 'rule-1';
ruleFromFileSystem1.version = 2;
const installedRule1 = getRuleMock(getQueryRuleParams());
installedRule1.params.ruleId = 'rule-1';
installedRule1.params.version = 1;
installedRule1.params.exceptionsList = [
{
id: 'endpoint_list',
list_id: 'endpoint_list',
namespace_type: 'agnostic',
type: 'endpoint',
},
];
const update = mergeExceptionLists(ruleFromFileSystem1, [installedRule1]);
expect(update.exceptions_list).toEqual(installedRule1.params.exceptionsList);
});
});

View file

@ -14,8 +14,7 @@ import { PartialFilter } from '../types';
export const installPrepackagedRules = (
rulesClient: RulesClient,
rules: AddPrepackagedRulesSchemaDecoded[],
outputIndex: string,
isRuleRegistryEnabled: boolean
outputIndex: string
): Array<Promise<SanitizedRule<RuleTypeParams>>> =>
rules.reduce<Array<Promise<SanitizedRule<RuleTypeParams>>>>((acc, rule) => {
const {
@ -72,7 +71,6 @@ export const installPrepackagedRules = (
return [
...acc,
createRules({
isRuleRegistryEnabled,
rulesClient,
anomalyThreshold,
author,

View file

@ -5,12 +5,13 @@
* 2.0.
*/
import { PatchRulesOptions } from './types';
import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks';
import { getAlertMock } from '../routes/__mocks__/request_responses';
import { PatchRulesOptions } from './types';
import { getRuleMock } from '../routes/__mocks__/request_responses';
import { getMlRuleParams, getQueryRuleParams } from '../schemas/rule_schemas.mock';
export const getPatchRulesOptionsMock = (isRuleRegistryEnabled: boolean): PatchRulesOptions => ({
export const getPatchRulesOptionsMock = (): PatchRulesOptions => ({
author: ['Elastic'],
buildingBlockType: undefined,
rulesClient: rulesClientMock.create(),
@ -59,10 +60,10 @@ export const getPatchRulesOptionsMock = (isRuleRegistryEnabled: boolean): PatchR
version: 1,
exceptionsList: [],
actions: [],
rule: getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
rule: getRuleMock(getQueryRuleParams()),
});
export const getPatchMlRulesOptionsMock = (isRuleRegistryEnabled: boolean): PatchRulesOptions => ({
export const getPatchMlRulesOptionsMock = (): PatchRulesOptions => ({
author: ['Elastic'],
buildingBlockType: undefined,
rulesClient: rulesClientMock.create(),
@ -111,5 +112,5 @@ export const getPatchMlRulesOptionsMock = (isRuleRegistryEnabled: boolean): Patc
version: 1,
exceptionsList: [],
actions: [],
rule: getAlertMock(isRuleRegistryEnabled, getMlRuleParams()),
rule: getRuleMock(getMlRuleParams()),
});

View file

@ -5,25 +5,23 @@
* 2.0.
*/
import { RulesClientMock } from '@kbn/alerting-plugin/server/rules_client.mock';
import { patchRules } from './patch_rules';
import { getPatchRulesOptionsMock, getPatchMlRulesOptionsMock } from './patch_rules.mock';
import { PatchRulesOptions } from './types';
import { RulesClientMock } from '@kbn/alerting-plugin/server/rules_client.mock';
import { getAlertMock } from '../routes/__mocks__/request_responses';
import { getRuleMock } from '../routes/__mocks__/request_responses';
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
describe.each([
['Legacy', false],
['RAC', true],
])('patchRules - %s', (_, isRuleRegistryEnabled) => {
describe('patchRules', () => {
it('should call rulesClient.disable if the rule was enabled and enabled is false', async () => {
const rulesOptionsMock = getPatchRulesOptionsMock(isRuleRegistryEnabled);
const rulesOptionsMock = getPatchRulesOptionsMock();
const ruleOptions: PatchRulesOptions = {
...rulesOptionsMock,
enabled: false,
};
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
getRuleMock(getQueryRuleParams())
);
await patchRules(ruleOptions);
expect(ruleOptions.rulesClient.disable).toHaveBeenCalledWith(
@ -34,7 +32,7 @@ describe.each([
});
it('should call rulesClient.enable if the rule was disabled and enabled is true', async () => {
const rulesOptionsMock = getPatchRulesOptionsMock(isRuleRegistryEnabled);
const rulesOptionsMock = getPatchRulesOptionsMock();
const ruleOptions: PatchRulesOptions = {
...rulesOptionsMock,
enabled: true,
@ -43,7 +41,7 @@ describe.each([
ruleOptions.rule.enabled = false;
}
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
getRuleMock(getQueryRuleParams())
);
await patchRules(ruleOptions);
expect(ruleOptions.rulesClient.enable).toHaveBeenCalledWith(
@ -54,7 +52,7 @@ describe.each([
});
it('calls the rulesClient with legacy ML params', async () => {
const rulesOptionsMock = getPatchMlRulesOptionsMock(isRuleRegistryEnabled);
const rulesOptionsMock = getPatchMlRulesOptionsMock();
const ruleOptions: PatchRulesOptions = {
...rulesOptionsMock,
enabled: true,
@ -63,7 +61,7 @@ describe.each([
ruleOptions.rule.enabled = false;
}
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
getRuleMock(getQueryRuleParams())
);
await patchRules(ruleOptions);
expect(ruleOptions.rulesClient.update).toHaveBeenCalledWith(
@ -79,7 +77,7 @@ describe.each([
});
it('calls the rulesClient with new ML params', async () => {
const rulesOptionsMock = getPatchMlRulesOptionsMock(isRuleRegistryEnabled);
const rulesOptionsMock = getPatchMlRulesOptionsMock();
const ruleOptions: PatchRulesOptions = {
...rulesOptionsMock,
machineLearningJobId: ['new_job_1', 'new_job_2'],
@ -89,7 +87,7 @@ describe.each([
ruleOptions.rule.enabled = false;
}
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
getRuleMock(getQueryRuleParams())
);
await patchRules(ruleOptions);
expect(ruleOptions.rulesClient.update).toHaveBeenCalledWith(
@ -106,7 +104,7 @@ describe.each([
describe('regression tests', () => {
it("updates the rule's actions if provided", async () => {
const rulesOptionsMock = getPatchRulesOptionsMock(isRuleRegistryEnabled);
const rulesOptionsMock = getPatchRulesOptionsMock();
const ruleOptions: PatchRulesOptions = {
...rulesOptionsMock,
actions: [
@ -121,7 +119,7 @@ describe.each([
],
};
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
getRuleMock(getQueryRuleParams())
);
await patchRules(ruleOptions);
expect(ruleOptions.rulesClient.update).toHaveBeenCalledWith(
@ -143,7 +141,7 @@ describe.each([
});
it('does not update actions if none are specified', async () => {
const ruleOptions = getPatchRulesOptionsMock(isRuleRegistryEnabled);
const ruleOptions = getPatchRulesOptionsMock();
delete ruleOptions.actions;
if (ruleOptions.rule != null) {
ruleOptions.rule.actions = [
@ -158,7 +156,7 @@ describe.each([
];
}
(ruleOptions.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
getRuleMock(getQueryRuleParams())
);
await patchRules(ruleOptions);
expect(ruleOptions.rulesClient.update).toHaveBeenCalledWith(

View file

@ -8,8 +8,8 @@
import { readRules } from './read_rules';
import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks';
import {
resolveAlertMock,
getAlertMock,
resolveRuleMock,
getRuleMock,
getFindResultWithSingleHit,
} from '../routes/__mocks__/request_responses';
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
@ -25,10 +25,7 @@ export class TestError extends Error {
public output: { statusCode: number };
}
describe.each([
['Legacy', false],
['RAC', true],
])('read_rules - %s', (_, isRuleRegistryEnabled) => {
describe('read_rules', () => {
beforeEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
@ -37,27 +34,23 @@ describe.each([
describe('readRules', () => {
test('should return the output from rulesClient if id is set but ruleId is undefined', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.resolve.mockResolvedValue(
resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
);
rulesClient.resolve.mockResolvedValue(resolveRuleMock(getQueryRuleParams()));
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
ruleId: undefined,
});
expect(rule).toEqual(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
expect(rule).toEqual(getRuleMock(getQueryRuleParams()));
});
test('should return null if saved object found by alerts client given id is not alert type', async () => {
const rulesClient = rulesClientMock.create();
const result = resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result = resolveRuleMock(getQueryRuleParams());
// @ts-expect-error
delete result.alertTypeId;
rulesClient.resolve.mockResolvedValue(result);
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
ruleId: undefined,
@ -72,7 +65,6 @@ describe.each([
});
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
ruleId: undefined,
@ -87,7 +79,6 @@ describe.each([
});
try {
await readRules({
isRuleRegistryEnabled,
rulesClient,
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
ruleId: undefined,
@ -99,25 +90,23 @@ describe.each([
test('should return the output from rulesClient if id is undefined but ruleId is set', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.get.mockResolvedValue(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
rulesClient.get.mockResolvedValue(getRuleMock(getQueryRuleParams()));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
id: undefined,
ruleId: 'rule-1',
});
expect(rule).toEqual(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
expect(rule).toEqual(getRuleMock(getQueryRuleParams()));
});
test('should return null if the output from rulesClient with ruleId set is empty', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.get.mockResolvedValue(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
rulesClient.get.mockResolvedValue(getRuleMock(getQueryRuleParams()));
rulesClient.find.mockResolvedValue({ data: [], page: 0, perPage: 1, total: 0 });
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
id: undefined,
ruleId: 'rule-1',
@ -127,25 +116,23 @@ describe.each([
test('should return the output from rulesClient if id is null but ruleId is set', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.get.mockResolvedValue(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
rulesClient.get.mockResolvedValue(getRuleMock(getQueryRuleParams()));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
id: undefined,
ruleId: 'rule-1',
});
expect(rule).toEqual(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
expect(rule).toEqual(getRuleMock(getQueryRuleParams()));
});
test('should return null if id and ruleId are undefined', async () => {
const rulesClient = rulesClientMock.create();
rulesClient.get.mockResolvedValue(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
rulesClient.get.mockResolvedValue(getRuleMock(getQueryRuleParams()));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
const rule = await readRules({
isRuleRegistryEnabled,
rulesClient,
id: undefined,
ruleId: undefined,

View file

@ -20,7 +20,6 @@ import { isAlertType, ReadRuleOptions } from './types';
* a filter query against the tags using `alert.attributes.tags: "__internal:${ruleId}"]`
*/
export const readRules = async ({
isRuleRegistryEnabled,
rulesClient,
id,
ruleId,
@ -30,7 +29,7 @@ export const readRules = async ({
if (id != null) {
try {
const rule = await rulesClient.resolve({ id });
if (isAlertType(isRuleRegistryEnabled, rule)) {
if (isAlertType(rule)) {
if (rule?.outcome === 'exactMatch') {
const { outcome, ...restOfRule } = rule;
return restOfRule;
@ -49,7 +48,6 @@ export const readRules = async ({
}
} else if (ruleId != null) {
const ruleFromFind = await findRules({
isRuleRegistryEnabled,
rulesClient,
filter: `alert.attributes.tags: "${INTERNAL_RULE_ID_KEY}:${ruleId}"`,
page: 1,
@ -58,10 +56,7 @@ export const readRules = async ({
sortField: undefined,
sortOrder: undefined,
});
if (
ruleFromFind.data.length === 0 ||
!isAlertType(isRuleRegistryEnabled, ruleFromFind.data[0])
) {
if (ruleFromFind.data.length === 0 || !isAlertType(ruleFromFind.data[0])) {
return null;
} else {
return ruleFromFind.data[0];

View file

@ -39,7 +39,7 @@ import type {
ThrottleOrNull,
} from '@kbn/securitysolution-io-ts-alerting-types';
import type { VersionOrUndefined, Version } from '@kbn/securitysolution-io-ts-types';
import { SIGNALS_ID, ruleTypeMappings } from '@kbn/securitysolution-rules';
import { ruleTypeMappings } from '@kbn/securitysolution-rules';
import type { ListArrayOrUndefined, ListArray } from '@kbn/securitysolution-io-ts-list-types';
import { RulesClient, PartialRule } from '@kbn/alerting-plugin/server';
@ -125,20 +125,16 @@ export interface Clients {
}
export const isAlertTypes = (
isRuleRegistryEnabled: boolean,
partialAlert: Array<PartialRule<RuleParams>>
): partialAlert is RuleAlertType[] => {
return partialAlert.every((rule) => isAlertType(isRuleRegistryEnabled, rule));
return partialAlert.every((rule) => isAlertType(rule));
};
export const isAlertType = (
isRuleRegistryEnabled: boolean,
partialAlert: PartialRule<RuleParams>
): partialAlert is RuleAlertType => {
const ruleTypeValues = Object.values(ruleTypeMappings) as unknown as string[];
return isRuleRegistryEnabled
? ruleTypeValues.includes(partialAlert.alertTypeId as string)
: partialAlert.alertTypeId === SIGNALS_ID;
return ruleTypeValues.includes(partialAlert.alertTypeId as string);
};
export interface CreateRulesOptions {
@ -192,7 +188,6 @@ export interface CreateRulesOptions {
version: Version;
exceptionsList: ListArray;
actions: RuleAlertAction[];
isRuleRegistryEnabled: boolean;
namespace?: NamespaceOrUndefined;
id?: string;
}
@ -261,7 +256,6 @@ interface PatchRulesFieldsOptions {
}
export interface ReadRuleOptions {
isRuleRegistryEnabled: boolean;
rulesClient: RulesClient;
id: IdOrUndefined;
ruleId: RuleIdOrUndefined;
@ -274,7 +268,6 @@ export interface DeleteRuleOptions {
}
export interface FindRuleOptions {
isRuleRegistryEnabled: boolean;
rulesClient: RulesClient;
perPage: PerPageOrUndefined;
page: PageOrUndefined;

View file

@ -15,10 +15,7 @@ import { ruleExecutionLogMock } from '../rule_execution_log/__mocks__';
jest.mock('./patch_rules');
describe.each([
['Legacy', false],
['RAC', true],
])('updatePrepackagedRules - %s', (_, isRuleRegistryEnabled) => {
describe('updatePrepackagedRules', () => {
let rulesClient: ReturnType<typeof rulesClientMock.create>;
let savedObjectsClient: ReturnType<typeof savedObjectsClientMock.create>;
let ruleExecutionLog: ReturnType<typeof ruleExecutionLogMock.forRoutes.create>;
@ -40,14 +37,13 @@ describe.each([
];
const outputIndex = 'outputIndex';
const prepackagedRule = getAddPrepackagedRulesSchemaDecodedMock();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
await updatePrepackagedRules(
rulesClient,
savedObjectsClient,
[{ ...prepackagedRule, actions }],
outputIndex,
isRuleRegistryEnabled,
ruleExecutionLog
);
@ -71,14 +67,13 @@ describe.each([
threat_query: 'threat:*',
};
const prepackagedRule = getAddPrepackagedRulesSchemaDecodedMock();
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
await updatePrepackagedRules(
rulesClient,
savedObjectsClient,
[{ ...prepackagedRule, ...updatedThreatParams }],
'output-index',
isRuleRegistryEnabled,
ruleExecutionLog
);

View file

@ -35,7 +35,6 @@ export const updatePrepackagedRules = async (
savedObjectsClient: SavedObjectsClientContract,
rules: AddPrepackagedRulesSchemaDecoded[],
outputIndex: string,
isRuleRegistryEnabled: boolean,
ruleExecutionLog: IRuleExecutionLogForRoutes
): Promise<void> => {
const ruleChunks = chunk(MAX_RULES_TO_UPDATE_IN_PARALLEL, rules);
@ -45,7 +44,6 @@ export const updatePrepackagedRules = async (
savedObjectsClient,
ruleChunk,
outputIndex,
isRuleRegistryEnabled,
ruleExecutionLog
);
await Promise.all(rulePromises);
@ -65,7 +63,6 @@ export const createPromises = (
savedObjectsClient: SavedObjectsClientContract,
rules: AddPrepackagedRulesSchemaDecoded[],
outputIndex: string,
isRuleRegistryEnabled: boolean,
ruleExecutionLog: IRuleExecutionLogForRoutes
): Array<Promise<PartialRule<RuleParams> | null>> => {
return rules.map(async (rule) => {
@ -118,7 +115,6 @@ export const createPromises = (
} = rule;
const existingRule = await readRules({
isRuleRegistryEnabled,
rulesClient,
ruleId,
id: undefined,
@ -149,7 +145,6 @@ export const createPromises = (
return (await createRules({
id: migratedRule.id,
isRuleRegistryEnabled,
rulesClient,
anomalyThreshold,
author,

View file

@ -11,27 +11,25 @@ import {
getUpdateMachineLearningSchemaMock,
getUpdateRulesSchemaMock,
} from '../../../../common/detection_engine/schemas/request/rule_schemas.mock';
import { getAlertMock } from '../routes/__mocks__/request_responses';
import { getRuleMock } from '../routes/__mocks__/request_responses';
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
export const getUpdateRulesOptionsMock = (isRuleRegistryEnabled: boolean) => ({
export const getUpdateRulesOptionsMock = () => ({
spaceId: 'default',
rulesClient: rulesClientMock.create(),
savedObjectsClient: savedObjectsClientMock.create(),
defaultOutputIndex: '.siem-signals-default',
existingRule: getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
migratedRule: getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
existingRule: getRuleMock(getQueryRuleParams()),
migratedRule: getRuleMock(getQueryRuleParams()),
ruleUpdate: getUpdateRulesSchemaMock(),
isRuleRegistryEnabled,
});
export const getUpdateMlRulesOptionsMock = (isRuleRegistryEnabled: boolean) => ({
export const getUpdateMlRulesOptionsMock = () => ({
spaceId: 'default',
rulesClient: rulesClientMock.create(),
savedObjectsClient: savedObjectsClientMock.create(),
defaultOutputIndex: '.siem-signals-default',
existingRule: getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
migratedRule: getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()),
existingRule: getRuleMock(getQueryRuleParams()),
migratedRule: getRuleMock(getQueryRuleParams()),
ruleUpdate: getUpdateMachineLearningSchemaMock(),
isRuleRegistryEnabled,
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { getAlertMock, resolveAlertMock } from '../routes/__mocks__/request_responses';
import { getRuleMock, resolveRuleMock } from '../routes/__mocks__/request_responses';
import { updateRules } from './update_rules';
import { getUpdateRulesOptionsMock, getUpdateMlRulesOptionsMock } from './update_rules.mock';
import { RulesClientMock } from '@kbn/alerting-plugin/server/rules_client.mock';
@ -14,10 +14,10 @@ import { getMlRuleParams, getQueryRuleParams } from '../schemas/rule_schemas.moc
// Failing with rule registry enabled
describe('updateRules', () => {
it('should call rulesClient.disable if the rule was enabled and enabled is false', async () => {
const rulesOptionsMock = getUpdateRulesOptionsMock(true);
const rulesOptionsMock = getUpdateRulesOptionsMock();
rulesOptionsMock.ruleUpdate.enabled = false;
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(true, getQueryRuleParams())
getRuleMock(getQueryRuleParams())
);
await updateRules(rulesOptionsMock);
@ -30,7 +30,7 @@ describe('updateRules', () => {
});
it('should call rulesClient.enable if the rule was disabled and enabled is true', async () => {
const baseRulesOptionsMock = getUpdateRulesOptionsMock(true);
const baseRulesOptionsMock = getUpdateRulesOptionsMock();
const rulesOptionsMock = {
...baseRulesOptionsMock,
existingRule: {
@ -41,7 +41,7 @@ describe('updateRules', () => {
rulesOptionsMock.ruleUpdate.enabled = true;
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(true, getQueryRuleParams())
getRuleMock(getQueryRuleParams())
);
await updateRules(rulesOptionsMock);
@ -54,15 +54,15 @@ describe('updateRules', () => {
});
it('calls the rulesClient with params', async () => {
const rulesOptionsMock = getUpdateMlRulesOptionsMock(true);
const rulesOptionsMock = getUpdateMlRulesOptionsMock();
rulesOptionsMock.ruleUpdate.enabled = true;
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue(
getAlertMock(true, getMlRuleParams())
getRuleMock(getMlRuleParams())
);
(rulesOptionsMock.rulesClient as unknown as RulesClientMock).resolve.mockResolvedValue(
resolveAlertMock(true, getMlRuleParams())
resolveRuleMock(getMlRuleParams())
);
await updateRules(rulesOptionsMock);

View file

@ -7,7 +7,7 @@
import uuid from 'uuid';
import { SIGNALS_ID, ruleTypeMappings } from '@kbn/securitysolution-rules';
import { ruleTypeMappings } from '@kbn/securitysolution-rules';
import { ResolvedSanitizedRule, SanitizedRule } from '@kbn/alerting-plugin/common';
import {
@ -127,15 +127,14 @@ export const typeSpecificSnakeToCamel = (params: CreateTypeSpecific): TypeSpecif
export const convertCreateAPIToInternalSchema = (
input: CreateRulesSchema,
siemClient: AppClient,
isRuleRegistryEnabled: boolean
siemClient: AppClient
): InternalRuleCreate => {
const typeSpecificParams = typeSpecificSnakeToCamel(input);
const newRuleId = input.rule_id ?? uuid.v4();
return {
name: input.name,
tags: addTags(input.tags ?? [], newRuleId, false),
alertTypeId: isRuleRegistryEnabled ? ruleTypeMappings[input.type] : SIGNALS_ID,
alertTypeId: ruleTypeMappings[input.type],
consumer: SERVER_APP_ID,
params: {
author: input.author ?? [],

View file

@ -15,9 +15,6 @@ import {
} from '@kbn/alerting-plugin/server';
import { buildEqlSearchRequest } from '../build_events_query';
import { hasLargeValueItem } from '../../../../../common/detection_engine/utils';
import { isOutdated } from '../../migrations/helpers';
import { getIndexVersion } from '../../routes/index/get_index_version';
import { MIN_EQL_RULE_INDEX_VERSION } from '../../routes/index/get_signals_template';
import { getInputIndex } from '../get_input_output_index';
import {
@ -71,27 +68,7 @@ export const eqlExecutor = async ({
);
result.warning = true;
}
if (!experimentalFeatures.ruleRegistryEnabled) {
try {
const signalIndexVersion = await getIndexVersion(
services.scopedClusterClient.asCurrentUser,
ruleParams.outputIndex
);
if (isOutdated({ current: signalIndexVersion, target: MIN_EQL_RULE_INDEX_VERSION })) {
throw new Error(
`EQL based rules require an update to version ${MIN_EQL_RULE_INDEX_VERSION} of the detection alerts index mapping`
);
}
} catch (err) {
if (err.statusCode === 403) {
throw new Error(
`EQL based rules require the user that created it to have the view_index_metadata, read, and write permissions for index: ${ruleParams.outputIndex}`
);
} else {
throw err;
}
}
}
const inputIndex = await getInputIndex({
experimentalFeatures,
services,

View file

@ -6,27 +6,25 @@
*/
import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks';
import { getAlertMock, getFindResultWithMultiHits } from '../routes/__mocks__/request_responses';
import { getRuleMock, getFindResultWithMultiHits } from '../routes/__mocks__/request_responses';
import { INTERNAL_RULE_ID_KEY, INTERNAL_IDENTIFIER } from '../../../../common/constants';
import { readRawTags, readTags, convertTagsToSet, convertToTags, isTags } from './read_tags';
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
describe.each([
['Legacy', false],
['RAC', true],
])('read_tags - %s', (_, isRuleRegistryEnabled) => {
describe('read_tags', () => {
afterEach(() => {
jest.resetAllMocks();
});
describe('readRawTags', () => {
test('it should return the intersection of tags to where none are repeating', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 2', 'tag 3'];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = ['tag 1', 'tag 2', 'tag 3', 'tag 4'];
@ -34,17 +32,17 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] }));
const tags = await readRawTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readRawTags({ rulesClient });
expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']);
});
test('it should return the intersection of tags to where some are repeating values', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3'];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4'];
@ -52,17 +50,17 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] }));
const tags = await readRawTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readRawTags({ rulesClient });
expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']);
});
test('it should work with no tags defined between two results', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = [];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = [];
@ -70,12 +68,12 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] }));
const tags = await readRawTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readRawTags({ rulesClient });
expect(tags).toEqual([]);
});
test('it should work with a single tag which has repeating values in it', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 1', 'tag 1', 'tag 2'];
@ -83,12 +81,12 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] }));
const tags = await readRawTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readRawTags({ rulesClient });
expect(tags).toEqual(['tag 1', 'tag 2']);
});
test('it should work with a single tag which has empty tags', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = [];
@ -96,19 +94,19 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] }));
const tags = await readRawTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readRawTags({ rulesClient });
expect(tags).toEqual([]);
});
});
describe('readTags', () => {
test('it should return the intersection of tags to where none are repeating', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 2', 'tag 3'];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = ['tag 1', 'tag 2', 'tag 3', 'tag 4'];
@ -116,17 +114,17 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] }));
const tags = await readTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readTags({ rulesClient });
expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']);
});
test('it should return the intersection of tags to where some are repeating values', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3'];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4'];
@ -134,17 +132,17 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] }));
const tags = await readTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readTags({ rulesClient });
expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']);
});
test('it should work with no tags defined between two results', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = [];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = [];
@ -152,12 +150,12 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] }));
const tags = await readTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readTags({ rulesClient });
expect(tags).toEqual([]);
});
test('it should work with a single tag which has repeating values in it', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 1', 'tag 1', 'tag 2'];
@ -165,12 +163,12 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] }));
const tags = await readTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readTags({ rulesClient });
expect(tags).toEqual(['tag 1', 'tag 2']);
});
test('it should work with a single tag which has empty tags', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = [];
@ -178,12 +176,12 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] }));
const tags = await readTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readTags({ rulesClient });
expect(tags).toEqual([]);
});
test('it should filter out any __internal tags for things such as alert_id', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = [
@ -195,12 +193,12 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] }));
const tags = await readTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readTags({ rulesClient });
expect(tags).toEqual(['tag 1']);
});
test('it should filter out any __internal tags with two different results', async () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = [
@ -213,7 +211,7 @@ describe.each([
'tag 5',
];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = [
@ -228,19 +226,19 @@ describe.each([
const rulesClient = rulesClientMock.create();
rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] }));
const tags = await readTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readTags({ rulesClient });
expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4', 'tag 5']);
});
});
describe('convertTagsToSet', () => {
test('it should convert the intersection of two tag systems without duplicates', () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3'];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4'];
@ -258,12 +256,12 @@ describe.each([
describe('convertToTags', () => {
test('it should convert the two tag systems together with duplicates', () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3'];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result2.params.ruleId = 'rule-2';
result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4'];
@ -284,18 +282,18 @@ describe.each([
});
test('it should filter out anything that is not a tag', () => {
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result1 = getRuleMock(getQueryRuleParams());
result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result1.params.ruleId = 'rule-1';
result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3'];
const result2 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result2 = getRuleMock(getQueryRuleParams());
result2.id = '99979e67-19a7-455f-b452-8eded6135716';
result2.params.ruleId = 'rule-2';
// @ts-expect-error
delete result2.tags;
const result3 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
const result3 = getRuleMock(getQueryRuleParams());
result3.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d';
result3.params.ruleId = 'rule-2';
result3.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4'];

View file

@ -40,27 +40,22 @@ export const convertTagsToSet = (tagObjects: object[]): Set<string> => {
// then this should be replaced with a an aggregation call.
// Ref: https://www.elastic.co/guide/en/kibana/master/saved-objects-api.html
export const readTags = async ({
isRuleRegistryEnabled,
rulesClient,
}: {
isRuleRegistryEnabled: boolean;
rulesClient: RulesClient;
}): Promise<string[]> => {
const tags = await readRawTags({ isRuleRegistryEnabled, rulesClient });
const tags = await readRawTags({ rulesClient });
return tags.filter((tag) => !tag.startsWith(INTERNAL_IDENTIFIER));
};
export const readRawTags = async ({
isRuleRegistryEnabled,
rulesClient,
}: {
isRuleRegistryEnabled: boolean;
rulesClient: RulesClient;
perPage?: number;
}): Promise<string[]> => {
// Get just one record so we can get the total count
const firstTags = await findRules({
isRuleRegistryEnabled,
rulesClient,
fields: ['tags'],
perPage: 1,
@ -71,7 +66,6 @@ export const readRawTags = async ({
});
// Get all the rules to aggregate over all the tags of the rules
const rules = await findRules({
isRuleRegistryEnabled,
rulesClient,
fields: ['tags'],
perPage: firstTags.total,

View file

@ -26,10 +26,7 @@ import { ImportTimelineResultSchema } from '../../../../../../common/types/timel
jest.mock('../../timelines/import_timelines/helpers');
describe.each([
['Legacy', false],
['RAC', true],
])('installPrepackagedTimelines - %s', (_, isRuleRegistryEnabled) => {
describe('installPrepackagedTimelines', () => {
let securitySetup: SecurityPluginSetup;
let frameworkRequest: FrameworkRequest;
const spyInstallPrepackagedTimelines = jest.spyOn(helpers, 'installPrepackagedTimelines');
@ -47,7 +44,7 @@ describe.each([
authz: {},
} as unknown as SecurityPluginSetup;
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit());
jest.doMock('./helpers', () => {
return {

View file

@ -8,7 +8,6 @@
import { Observable } from 'rxjs';
import LRU from 'lru-cache';
import {
SIGNALS_ID,
QUERY_RULE_TYPE_ID,
INDICATOR_RULE_TYPE_ID,
ML_RULE_TYPE_ID,
@ -177,9 +176,6 @@ export class Plugin implements ISecuritySolutionPlugin {
this.telemetryUsageCounter = plugins.usageCollection?.createUsageCounter(APP_ID);
// TODO: Once we are past experimental phase this check can be removed along with legacy registration of rules
const isRuleRegistryEnabled = experimentalFeatures.ruleRegistryEnabled;
const { ruleDataService } = plugins.ruleRegistry;
let ruleDataClient: IRuleDataClient | null = null;
let previewRuleDataClient: IRuleDataClient | null = null;
@ -271,7 +267,8 @@ export class Plugin implements ISecuritySolutionPlugin {
registerPolicyRoutes(router, endpointContext);
registerActionRoutes(router, endpointContext);
const racRuleTypes = [
const ruleTypes = [
LEGACY_NOTIFICATIONS_ID,
EQL_RULE_TYPE_ID,
INDICATOR_RULE_TYPE_ID,
ML_RULE_TYPE_ID,
@ -279,11 +276,6 @@ export class Plugin implements ISecuritySolutionPlugin {
SAVED_QUERY_RULE_TYPE_ID,
THRESHOLD_RULE_TYPE_ID,
];
const ruleTypes = [
SIGNALS_ID,
LEGACY_NOTIFICATIONS_ID,
...(isRuleRegistryEnabled ? racRuleTypes : []),
];
plugins.features.registerKibanaFeature(getKibanaPrivilegesFeaturePrivileges(ruleTypes));
plugins.features.registerKibanaFeature(getCasesKibanaFeature());

View file

@ -86,15 +86,14 @@ export const initRoutes = (
previewRuleDataClient: IRuleDataClient,
previewTelemetryReceiver: ITelemetryReceiver
) => {
const isRuleRegistryEnabled = ruleDataClient != null;
// Detection Engine Rule routes that have the REST endpoints of /api/detection_engine/rules
// All REST rule creation, deletion, updating, etc
createRulesRoute(router, ml, isRuleRegistryEnabled);
readRulesRoute(router, logger, isRuleRegistryEnabled);
updateRulesRoute(router, ml, isRuleRegistryEnabled);
patchRulesRoute(router, ml, isRuleRegistryEnabled);
deleteRulesRoute(router, isRuleRegistryEnabled);
findRulesRoute(router, logger, isRuleRegistryEnabled);
createRulesRoute(router, ml);
readRulesRoute(router, logger);
updateRulesRoute(router, ml);
patchRulesRoute(router, ml);
deleteRulesRoute(router);
findRulesRoute(router, logger);
previewRulesRoute(
router,
config,
@ -110,19 +109,19 @@ export const initRoutes = (
legacyCreateLegacyNotificationRoute(router, logger);
addPrepackedRulesRoute(router);
getPrepackagedRulesStatusRoute(router, config, security, isRuleRegistryEnabled);
createRulesBulkRoute(router, ml, isRuleRegistryEnabled, logger);
updateRulesBulkRoute(router, ml, isRuleRegistryEnabled, logger);
patchRulesBulkRoute(router, ml, isRuleRegistryEnabled, logger);
deleteRulesBulkRoute(router, isRuleRegistryEnabled, logger);
performBulkActionRoute(router, ml, logger, isRuleRegistryEnabled);
getPrepackagedRulesStatusRoute(router, config, security);
createRulesBulkRoute(router, ml, logger);
updateRulesBulkRoute(router, ml, logger);
patchRulesBulkRoute(router, ml, logger);
deleteRulesBulkRoute(router, logger);
performBulkActionRoute(router, ml, logger);
getRuleExecutionEventsRoute(router);
createTimelinesRoute(router, config, security);
patchTimelinesRoute(router, config, security);
importRulesRoute(router, config, ml, isRuleRegistryEnabled);
exportRulesRoute(router, config, logger, isRuleRegistryEnabled);
importRulesRoute(router, config, ml);
exportRulesRoute(router, config, logger);
importTimelinesRoute(router, config, security);
exportTimelinesRoute(router, config, security);
@ -156,7 +155,7 @@ export const initRoutes = (
deleteIndexRoute(router);
// Detection Engine tags routes that have the REST endpoints of /api/detection_engine/tags
readTagsRoute(router, isRuleRegistryEnabled);
readTagsRoute(router);
// Privileges API to get the generic user privileges
readPrivilegesRoute(router, hasEncryptionKey);

View file

@ -37,7 +37,6 @@ export async function getApiIntegrationConfig({ readConfigFile }: FtrConfigProvi
'--xpack.ruleRegistry.write.cache.enabled=false',
'--xpack.uptime.service.password=test',
'--xpack.uptime.service.username=localKibanaIntegrationTestsUser',
`--xpack.securitySolution.enableExperimental=${JSON.stringify(['ruleRegistryEnabled'])}`,
],
},
esTestCluster: {

View file

@ -148,7 +148,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
: []),
'--xpack.ruleRegistry.write.enabled=true',
'--xpack.ruleRegistry.write.cache.enabled=false',
`--xpack.securitySolution.enableExperimental=${JSON.stringify(['ruleRegistryEnabled'])}`,
],
},
};

View file

@ -88,7 +88,10 @@ export default ({ getService }: FtrProviderContext): void => {
.expect(200);
const bodyToCompare = removeServerGeneratedProperties(body);
expect(bodyToCompare).to.eql(getSimpleRuleOutput('rule-1', false));
expect(bodyToCompare).to.eql({
...getSimpleRuleOutput('rule-1', false),
output_index: '',
});
});
it('should fail validation when importing a rule with malformed "from" params on the rules', async () => {
@ -317,7 +320,10 @@ export default ({ getService }: FtrProviderContext): void => {
.expect(200);
const bodyToCompare = removeServerGeneratedProperties(body);
const ruleOutput = getSimpleRuleOutput('rule-1');
const ruleOutput = {
...getSimpleRuleOutput('rule-1'),
output_index: '',
};
ruleOutput.name = 'some other name';
ruleOutput.version = 2;
expect(bodyToCompare).to.eql(ruleOutput);
@ -393,6 +399,10 @@ export default ({ getService }: FtrProviderContext): void => {
});
it('should be able to correctly read back a mixed import of different rules even if some cause conflicts', async () => {
const getRuleOutput = (name: string) => ({
...getSimpleRuleOutput(name),
output_index: '',
});
await supertest
.post(`${DETECTION_ENGINE_RULES_URL}/_import`)
.set('kbn-xsrf', 'true')
@ -425,9 +435,9 @@ export default ({ getService }: FtrProviderContext): void => {
const bodyToCompareOfRule3 = removeServerGeneratedProperties(bodyOfRule3);
expect([bodyToCompareOfRule1, bodyToCompareOfRule2, bodyToCompareOfRule3]).to.eql([
getSimpleRuleOutput('rule-1'),
getSimpleRuleOutput('rule-2'),
getSimpleRuleOutput('rule-3'),
getRuleOutput('rule-1'),
getRuleOutput('rule-2'),
getRuleOutput('rule-3'),
]);
});
});

View file

@ -75,7 +75,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
'--xpack.ruleRegistry.unsafe.indexUpgrade.enabled=true',
'--xpack.ruleRegistry.unsafe.legacyMultiTenancy.enabled=true',
`--xpack.securitySolution.enableExperimental=${JSON.stringify([
'ruleRegistryEnabled',
'previewTelemetryUrlEnabled',
])}`,
...(ssl

View file

@ -46,7 +46,7 @@ const getImportRuleBuffer = (connectorId: string) => {
risk_score: 21,
severity: 'low',
license: '',
output_index: '.siem-signals-devin-hurley-7',
output_index: '',
meta: { from: '1m', kibana_siem_app_url: 'http://0.0.0.0:5601/s/7/app/security' },
author: [],
false_positives: [],
@ -280,7 +280,10 @@ export default ({ getService }: FtrProviderContext): void => {
.expect(200);
const bodyToCompare = removeServerGeneratedProperties(body);
expect(bodyToCompare).to.eql(getSimpleRuleOutput('rule-1', false));
expect(bodyToCompare).to.eql({
...getSimpleRuleOutput('rule-1', false),
output_index: '',
});
});
it('should be able to import two rules', async () => {
@ -419,7 +422,10 @@ export default ({ getService }: FtrProviderContext): void => {
.expect(200);
const bodyToCompare = removeServerGeneratedProperties(body);
const ruleOutput = getSimpleRuleOutput('rule-1');
const ruleOutput = {
...getSimpleRuleOutput('rule-1'),
output_index: '',
};
ruleOutput.name = 'some other name';
ruleOutput.version = 2;
expect(bodyToCompare).to.eql(ruleOutput);
@ -495,6 +501,11 @@ export default ({ getService }: FtrProviderContext): void => {
});
it('should be able to correctly read back a mixed import of different rules even if some cause conflicts', async () => {
const simpleRuleOutput = (ruleName: string) => ({
...getSimpleRuleOutput(ruleName),
output_index: '',
});
await supertest
.post(`${DETECTION_ENGINE_RULES_URL}/_import`)
.set('kbn-xsrf', 'true')
@ -527,9 +538,9 @@ export default ({ getService }: FtrProviderContext): void => {
const bodyToCompareOfRule3 = removeServerGeneratedProperties(bodyOfRule3);
expect([bodyToCompareOfRule1, bodyToCompareOfRule2, bodyToCompareOfRule3]).to.eql([
getSimpleRuleOutput('rule-1'),
getSimpleRuleOutput('rule-2'),
getSimpleRuleOutput('rule-3'),
simpleRuleOutput('rule-1'),
simpleRuleOutput('rule-2'),
simpleRuleOutput('rule-3'),
]);
});

View file

@ -83,8 +83,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
...disabledPlugins
.filter((k) => k !== 'security')
.map((key) => `--xpack.${key}.enabled=false`),
// TO DO: Remove feature flags once we're good to go
'--xpack.securitySolution.enableExperimental=["ruleRegistryEnabled"]',
'--xpack.ruleRegistry.write.enabled=true',
`--server.xsrf.allowlist=${JSON.stringify(getAllExternalServiceSimulatorPaths())}`,
...(ssl

View file

@ -51,7 +51,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
`--xpack.securitySolution.enableExperimental=${JSON.stringify([
'riskyHostsEnabled',
'riskyUsersEnabled',
'ruleRegistryEnabled',
])}`,
`--home.disableWelcomeScreen=true`,
],

View file

@ -84,8 +84,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
...disabledPlugins
.filter((k) => k !== 'security')
.map((key) => `--xpack.${key}.enabled=false`),
// TO DO: Remove feature flags once we're good to go
'--xpack.securitySolution.enableExperimental=["ruleRegistryEnabled"]',
'--xpack.ruleRegistry.write.enabled=true',
'--xpack.security.audit.enabled=true',
'--xpack.security.audit.appender.type=file',