mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[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:
parent
80a2aa1f74
commit
414ad78ffa
86 changed files with 935 additions and 1490 deletions
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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 => ({
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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}`;
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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: {},
|
||||
});
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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: '',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()),
|
||||
});
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ?? [],
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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'];
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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'])}`,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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'),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'),
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -51,7 +51,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
`--xpack.securitySolution.enableExperimental=${JSON.stringify([
|
||||
'riskyHostsEnabled',
|
||||
'riskyUsersEnabled',
|
||||
'ruleRegistryEnabled',
|
||||
])}`,
|
||||
`--home.disableWelcomeScreen=true`,
|
||||
],
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue