diff --git a/.buildkite/ftr_security_serverless_configs.yml b/.buildkite/ftr_security_serverless_configs.yml index a9aa17fffc6b..2a2622c84523 100644 --- a/.buildkite/ftr_security_serverless_configs.yml +++ b/.buildkite/ftr_security_serverless_configs.yml @@ -88,6 +88,13 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_delete/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/configs/serverless_essentials_tier.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/configs/serverless_complete_tier.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/serverless_essentials_tier.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/configs/serverless_essentials_tier.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_read/trial_license_complete_tier/configs/serverless.config.ts diff --git a/.buildkite/ftr_security_stateful_configs.yml b/.buildkite/ftr_security_stateful_configs.yml index 65ccf94a9d6d..c61c5792c393 100644 --- a/.buildkite/ftr_security_stateful_configs.yml +++ b/.buildkite/ftr_security_stateful_configs.yml @@ -70,6 +70,13 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/basic_license_essentials_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/configs/ess_basic_license.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/configs/ess_enterprise_license.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/ess_basic_license.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/configs/ess_basic_license.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_read/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_read/basic_license_essentials_tier/configs/ess.config.ts diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx index 3f33675461ff..6962c66e69f4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx @@ -25,8 +25,8 @@ import { useDownloadExportedRules } from '../../../rule_management/logic/bulk_ac import { useHasActionsPrivileges } from './use_has_actions_privileges'; import type { TimeRange } from '../../../rule_gaps/types'; import { useScheduleRuleRun } from '../../../rule_gaps/logic/use_schedule_rule_run'; -import { usePrebuiltRulesCustomizationStatus } from '../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_customization_status'; import { ManualRuleRunEventTypes } from '../../../../common/lib/telemetry'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; export const useRulesTableActions = ({ showExceptionsDuplicateConfirmation, @@ -47,7 +47,9 @@ export const useRulesTableActions = ({ const { bulkExport } = useBulkExport(); const downloadExportedRules = useDownloadExportedRules(); const { scheduleRuleRun } = useScheduleRuleRun(); - const { isRulesCustomizationEnabled } = usePrebuiltRulesCustomizationStatus(); + const isPrebuiltRulesCustomizationFeatureFlagEnabled = useIsExperimentalFeatureEnabled( + 'prebuiltRulesCustomizationEnabled' + ); return [ { @@ -118,7 +120,7 @@ export const useRulesTableActions = ({ await downloadExportedRules(response); } }, - enabled: (rule: Rule) => isRulesCustomizationEnabled || !rule.immutable, + enabled: (rule: Rule) => isPrebuiltRulesCustomizationFeatureFlagEnabled || !rule.immutable, }, { type: 'icon', diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx index 66c0cfc49688..fe3bd350cd1e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx @@ -14,7 +14,6 @@ import { } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; -import { usePrebuiltRulesCustomizationStatus } from '../../../../detection_engine/rule_management/logic/prebuilt_rules/use_prebuilt_rules_customization_status'; import { useScheduleRuleRun } from '../../../../detection_engine/rule_gaps/logic/use_schedule_rule_run'; import type { TimeRange } from '../../../../detection_engine/rule_gaps/types'; import { APP_UI_ID, SecurityPageName } from '../../../../../common/constants'; @@ -36,6 +35,7 @@ import { useDownloadExportedRules } from '../../../../detection_engine/rule_mana import * as i18nActions from '../../../pages/detection_engine/rules/translations'; import * as i18n from './translations'; import { ManualRuleRunEventTypes } from '../../../../common/lib/telemetry'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; const MyEuiButtonIcon = styled(EuiButtonIcon)` &.euiButtonIcon { @@ -73,7 +73,9 @@ const RuleActionsOverflowComponent = ({ application: { navigateToApp }, telemetry, } = useKibana().services; - const { isRulesCustomizationEnabled } = usePrebuiltRulesCustomizationStatus(); + const isPrebuiltRulesCustomizationFeatureFlagEnabled = useIsExperimentalFeatureEnabled( + 'prebuiltRulesCustomizationEnabled' + ); const { startTransaction } = useStartTransaction(); const { executeBulkAction } = useExecuteBulkAction({ suppressSuccessToast: true }); const { bulkExport } = useBulkExport(); @@ -140,7 +142,8 @@ const RuleActionsOverflowComponent = ({ key={i18nActions.EXPORT_RULE} icon="exportAction" disabled={ - !userHasPermissions || (isRulesCustomizationEnabled === false && rule.immutable) + !userHasPermissions || + (isPrebuiltRulesCustomizationFeatureFlagEnabled === false && rule.immutable) } data-test-subj="rules-details-export-rule" onClick={async () => { @@ -210,7 +213,7 @@ const RuleActionsOverflowComponent = ({ rule, canDuplicateRuleWithActions, userHasPermissions, - isRulesCustomizationEnabled, + isPrebuiltRulesCustomizationFeatureFlagEnabled, startTransaction, closePopover, showBulkDuplicateExceptionsConfirmation, diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts index d8ffbb9f6830..484f6d321721 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts @@ -43,6 +43,7 @@ import { bulkEnableDisableRules } from './bulk_enable_disable_rules'; import { fetchRulesByQueryOrIds } from './fetch_rules_by_query_or_ids'; import { bulkScheduleBackfill } from './bulk_schedule_rule_run'; import { createPrebuiltRuleAssetsClient } from '../../../../prebuilt_rules/logic/rule_assets/prebuilt_rule_assets_client'; +import { PrebuiltRulesCustomizationDisabledReason } from '../../../../../../../common/detection_engine/prebuilt_rules/prebuilt_rule_customization_status'; const MAX_RULES_TO_PROCESS_TOTAL = 10000; // Set a lower limit for bulk edit as the rules client might fail with a "Query @@ -277,6 +278,14 @@ export const performBulkActionRoute = ( break; } case BulkActionTypeEnum.export: { + const prebuiltRulesCustomizationStatus = + detectionRulesClient.getRuleCustomizationStatus(); + + const isPrebuiltRulesExportAllowed = + prebuiltRulesCustomizationStatus.isRulesCustomizationEnabled || + prebuiltRulesCustomizationStatus.customizationDisabledReason === + PrebuiltRulesCustomizationDisabledReason.License; + const exported = await getExportByObjectIds( rulesClient, exceptionsClient, @@ -284,7 +293,7 @@ export const performBulkActionRoute = ( exporter, request, actionsClient, - detectionRulesClient.getRuleCustomizationStatus().isRulesCustomizationEnabled + isPrebuiltRulesExportAllowed ); const responseBody = `${exported.rulesNdjson}${exported.exceptionLists}${exported.actionConnectors}${exported.exportDetails}`; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts index aa4c69b32487..1a3afe7dd020 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts @@ -23,6 +23,7 @@ import { getExportByObjectIds } from '../../../logic/export/get_export_by_object import { getExportAll } from '../../../logic/export/get_export_all'; import { buildSiemResponse } from '../../../../routes/utils'; import { RULE_MANAGEMENT_IMPORT_EXPORT_SOCKET_TIMEOUT_MS } from '../../timeouts'; +import { PrebuiltRulesCustomizationDisabledReason } from '../../../../../../../common/detection_engine/prebuilt_rules/prebuilt_rule_customization_status'; export const exportRulesRoute = ( router: SecuritySolutionPluginRouter, @@ -73,7 +74,12 @@ export const exportRulesRoute = ( const client = getClient({ includedHiddenTypes: ['action'] }); const actionsExporter = getExporter(client); - const { isRulesCustomizationEnabled } = detectionRulesClient.getRuleCustomizationStatus(); + const prebuiltRulesCustomizationStatus = detectionRulesClient.getRuleCustomizationStatus(); + + const isPrebuiltRulesExportAllowed = + prebuiltRulesCustomizationStatus.isRulesCustomizationEnabled || + prebuiltRulesCustomizationStatus.customizationDisabledReason === + PrebuiltRulesCustomizationDisabledReason.License; try { const exportSizeLimit = config.maxRuleImportExportSize; @@ -85,7 +91,7 @@ export const exportRulesRoute = ( } else { let rulesCount = 0; - if (isRulesCustomizationEnabled) { + if (isPrebuiltRulesExportAllowed) { rulesCount = await getRulesCount({ rulesClient, filter: '', @@ -95,6 +101,7 @@ export const exportRulesRoute = ( rulesClient, }); } + if (rulesCount > exportSizeLimit) { return siemResponse.error({ statusCode: 400, @@ -112,7 +119,7 @@ export const exportRulesRoute = ( actionsExporter, request, actionsClient, - isRulesCustomizationEnabled + isPrebuiltRulesExportAllowed ) : await getExportAll( rulesClient, @@ -120,7 +127,7 @@ export const exportRulesRoute = ( actionsExporter, request, actionsClient, - isRulesCustomizationEnabled + isPrebuiltRulesExportAllowed ); const responseBody = request.query.exclude_export_details diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts index 820f1b8c493a..ceda79430825 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts @@ -31,6 +31,7 @@ import { getQueryRuleParams } from '../../../../rule_schema/mocks'; import { importRulesRoute } from './route'; import { HttpAuthzError } from '../../../../../machine_learning/validation'; import { createPrebuiltRuleAssetsClient as createPrebuiltRuleAssetsClientMock } from '../../../../prebuilt_rules/logic/rule_assets/__mocks__/prebuilt_rule_assets_client'; +import { PrebuiltRulesCustomizationDisabledReason } from '../../../../../../../common/detection_engine/prebuilt_rules/prebuilt_rule_customization_status'; jest.mock('../../../../../machine_learning/authz'); @@ -59,6 +60,7 @@ describe('Import rules route', () => { clients.detectionRulesClient.importRule.mockResolvedValue(getRulesSchemaMock()); clients.detectionRulesClient.getRuleCustomizationStatus.mockReturnValue({ isRulesCustomizationEnabled: false, + customizationDisabledReason: PrebuiltRulesCustomizationDisabledReason.FeatureFlag, }); clients.actionsClient.getAll.mockResolvedValue([]); context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( @@ -71,7 +73,6 @@ describe('Import rules route', () => { describe('status codes', () => { test('returns 200 when importing a single rule with a valid actionClient and alertClient', async () => { const response = await server.inject(request, requestContextMock.convertContext(context)); - expect(response.status).toEqual(200); }); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts index c5ab3b670085..de2c05802df1 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts @@ -39,6 +39,7 @@ import { migrateLegacyActionsIds, } from '../../../utils/utils'; import { RULE_MANAGEMENT_IMPORT_EXPORT_SOCKET_TIMEOUT_MS } from '../../timeouts'; +import { PrebuiltRulesCustomizationDisabledReason } from '../../../../../../../common/detection_engine/prebuilt_rules/prebuilt_rule_customization_status'; const CHUNK_PARSED_OBJECT_SIZE = 50; @@ -86,7 +87,7 @@ export const importRulesRoute = (router: SecuritySolutionPluginRouter, config: C ]); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); - const { isRulesCustomizationEnabled } = detectionRulesClient.getRuleCustomizationStatus(); + const ruleCustomizationStatus = detectionRulesClient.getRuleCustomizationStatus(); const actionsClient = ctx.actions.getActionsClient(); const actionSOClient = ctx.core.savedObjects.getClient({ includedHiddenTypes: ['action'], @@ -166,21 +167,24 @@ export const importRulesRoute = (router: SecuritySolutionPluginRouter, config: C let importRuleResponse: ImportRuleResponse[] = []; - if (isRulesCustomizationEnabled) { - importRuleResponse = await importRules({ + if ( + ruleCustomizationStatus.customizationDisabledReason === + PrebuiltRulesCustomizationDisabledReason.FeatureFlag + ) { + importRuleResponse = await importRulesLegacy({ ruleChunks, overwriteRules: request.query.overwrite, allowMissingConnectorSecrets: !!actionConnectors.length, - ruleSourceImporter, detectionRulesClient, + savedObjectsClient, }); } else { - importRuleResponse = await importRulesLegacy({ + importRuleResponse = await importRules({ ruleChunks, overwriteRules: request.query.overwrite, allowMissingConnectorSecrets: !!actionConnectors.length, + ruleSourceImporter, detectionRulesClient, - savedObjectsClient, }); } diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts index 2ffdf1b0dbc1..caec786fb2ab 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts @@ -104,7 +104,7 @@ export const validateBulkEditRule = async ({ } // Rule customization is disabled; only certain actions can be applied to immutable rules - const canRuleBeEdited = istEditApplicableToImmutableRule(edit); + const canRuleBeEdited = isEditApplicableToImmutableRule(edit); if (!canRuleBeEdited) { await throwDryRunError( () => invariant(canRuleBeEdited, "Elastic rule can't be edited"), @@ -120,7 +120,7 @@ export const validateBulkEditRule = async ({ /** * add_rule_actions, set_rule_actions can be applied to prebuilt/immutable rules */ -const istEditApplicableToImmutableRule = (edit: BulkActionEditPayload[]): boolean => { +const isEditApplicableToImmutableRule = (edit: BulkActionEditPayload[]): boolean => { const applicableActions: BulkActionEditType[] = [ BulkActionEditTypeEnum.set_rule_actions, BulkActionEditTypeEnum.add_rule_actions, diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/import_rules.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/import_rules.ts index 0a6681328929..72d78fbd4147 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/import_rules.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/import_rules.ts @@ -19,6 +19,7 @@ import { import { checkRuleExceptionReferences } from '../../import/check_rule_exception_references'; import { getReferencedExceptionLists } from '../../import/gather_referenced_exceptions'; import type { IDetectionRulesClient } from '../detection_rules_client_interface'; +import { PrebuiltRulesCustomizationDisabledReason } from '../../../../../../../common/detection_engine/prebuilt_rules/prebuilt_rule_customization_status'; /** * Imports rules @@ -39,6 +40,8 @@ export const importRules = async ({ rules: RuleToImport[]; savedObjectsClient: SavedObjectsClientContract; }): Promise> => { + const ruleCustomizationStatus = detectionRulesClient.getRuleCustomizationStatus(); + const existingLists = await getReferencedExceptionLists({ rules, savedObjectsClient, @@ -69,6 +72,25 @@ export const importRules = async ({ } const { immutable, ruleSource } = ruleSourceImporter.calculateRuleSource(rule); + const isCustomized = (ruleSource.type === 'external' && ruleSource.is_customized) ?? false; + + if ( + isCustomized && + ruleCustomizationStatus.customizationDisabledReason === + PrebuiltRulesCustomizationDisabledReason.License + ) { + return createRuleImportErrorObject({ + message: i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.licenseInsufficientToImportCustomizedPrebuiltRule', + { + defaultMessage: + 'Importing prebuilt rules is not supported if the they were modified. Upgrade your license to import modified prebuilt rules [rule_id: {ruleId}].', + values: { ruleId: rule.rule_id }, + } + ), + ruleId: rule.rule_id, + }); + } const [exceptionErrors, exceptions] = checkRuleExceptionReferences({ rule, diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts index 4407a15622cd..b8d341164c8c 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts @@ -24,15 +24,14 @@ export const getExportAll = async ( actionsExporter: ISavedObjectsExporter, request: KibanaRequest, actionsClient: ActionsClient, - prebuiltRulesCustomizationEnabled?: boolean + isPrebuiltRulesExportAllowed?: boolean ): Promise<{ rulesNdjson: string; exportDetails: string; exceptionLists: string | null; actionConnectors: string; - prebuiltRulesCustomizationEnabled?: boolean; }> => { - const ruleAlertTypes = prebuiltRulesCustomizationEnabled + const ruleAlertTypes = isPrebuiltRulesExportAllowed ? await getRules({ rulesClient, filter: '' }) : await getNonPackagedRules({ rulesClient }); const rules = transformAlertsToRules(ruleAlertTypes); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts index 02355d39e7e6..9924b4519c3f 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts @@ -30,19 +30,18 @@ export const getExportByObjectIds = async ( actionsExporter: ISavedObjectsExporter, request: KibanaRequest, actionsClient: ActionsClient, - prebuiltRulesCustomizationEnabled?: boolean + isPrebuiltRulesExportAllowed?: boolean ): Promise<{ rulesNdjson: string; exportDetails: string; exceptionLists: string | null; actionConnectors: string; - prebuiltRulesCustomizationEnabled?: boolean; }> => withSecuritySpan('getExportByObjectIds', async () => { const rulesAndErrors = await fetchRulesByIds( rulesClient, ruleIds, - prebuiltRulesCustomizationEnabled + isPrebuiltRulesExportAllowed ); const { rules, missingRuleIds } = rulesAndErrors; @@ -83,7 +82,7 @@ interface FetchRulesResult { const fetchRulesByIds = async ( rulesClient: RulesClient, ruleIds: string[], - prebuiltRulesCustomizationEnabled?: boolean + isPrebuiltRulesExportAllowed?: boolean ): Promise => { // It's important to avoid too many clauses in the request otherwise ES will fail to process the request // with `too_many_clauses` error (see https://github.com/elastic/kibana/issues/170015). The clauses limit @@ -117,7 +116,7 @@ const fetchRulesByIds = async ( return matchingRule != null && hasValidRuleType(matchingRule) && - (prebuiltRulesCustomizationEnabled || matchingRule.params.immutable !== true) + (isPrebuiltRulesExportAllowed || matchingRule.params.immutable !== true) ? { rule: transformRuleToExportableFormat(internalRuleToAPIResponse(matchingRule)), } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/ess.config.ts index c71cfab3cc9f..65cafaacac6d 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/ess.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/ess.config.ts @@ -16,7 +16,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...functionalConfig.getAll(), testFiles: [require.resolve('..')], junit: { - reportName: 'Rules Management - Rule Patch Integration Tests - ESS Env - Basic License', + reportName: + 'Rules Management - Rule Import/Export Integration Tests - ESS Env - Basic License', }, }; } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/serverless.config.ts index de3421e19030..a3f1d766fbfd 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/serverless.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/basic_license_essentials_tier/configs/serverless.config.ts @@ -11,6 +11,6 @@ export default createTestConfig({ testFiles: [require.resolve('..')], junit: { reportName: - 'Rules Management - Rule Patch Integration Tests - Serverless Env - Essentials Tier ', + 'Rules Management - Rule Import/Export Integration Tests - Serverless Env - Essentials Tier', }, }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts new file mode 100644 index 000000000000..f96b9fda5e84 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../../../config/ess/config.base.trial') + ); + + const testConfig = { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Prebuilt Rule Export Integration Tests - Customization disabled - ESS Env', + }, + }; + + return testConfig; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts new file mode 100644 index 000000000000..193ed2ea69e8 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Prebuilt Rule Export Integration Tests - Customization disabled - Serverless Env', + }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/export_prebuilt_rules_feature_disabled.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/export_prebuilt_rules_feature_disabled.ts new file mode 100644 index 000000000000..a206d850ed6c --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/export_prebuilt_rules_feature_disabled.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { BulkActionTypeEnum } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { + binaryToString, + createPrebuiltRuleAssetSavedObjects, + createRuleAssetSavedObject, + deleteAllPrebuiltRuleAssets, + installPrebuiltRules, +} from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const securitySolutionApi = getService('securitySolutionApi'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI Prebuilt rule export - feature disabled', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + it("Export API - doesn't export prebuilt rules when the feature is disabled", async () => { + const ruleId = 'prebuilt-rule-1'; + const ruleAsset = createRuleAssetSavedObject({ rule_id: ruleId, version: 1 }); + await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]); + await installPrebuiltRules(es, supertest); + + const { body } = await securitySolutionApi + .exportRules({ query: {}, body: null }) + .expect(200) + .parse(binaryToString); + + const exportDetails = JSON.parse(body.toString()); + + expect(exportDetails).toMatchObject({ + exported_rules_count: 0, + missing_rules: [], // Prebuilt rules are not in missing rules, even though they are not exported + }); + }); + + it("Bulk actions export API - doesn't export prebuilt rules when the feature is disabled", async () => { + const ruleAsset = createRuleAssetSavedObject({ rule_id: 'prebuilt-rule-1', version: 1 }); + await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]); + await installPrebuiltRules(es, supertest); + + const findResponse = await securitySolutionApi.findRules({ query: {} }); + const installedRule = findResponse.body.data[0]; + + const { body } = await securitySolutionApi + .performRulesBulkAction({ + query: {}, + body: { action: BulkActionTypeEnum.export, ids: [installedRule.id] }, + }) + .expect(200) + .parse(binaryToString); + + const exportDetails = JSON.parse(body.toString()); + + expect(exportDetails).toMatchObject({ + exported_rules_count: 0, + missing_rules: [{ rule_id: 'prebuilt-rule-1' }], + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/index.ts new file mode 100644 index 000000000000..4912e49337b3 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_disabled/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Rules Management - Prebuilt rule export', function () { + loadTestFile(require.resolve('./export_prebuilt_rules_feature_disabled')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/configs/ess_basic_license.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/configs/ess_basic_license.config.ts new file mode 100644 index 000000000000..780ea70647a1 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/configs/ess_basic_license.config.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../../../config/ess/config.base.trial') + ); + + const testConfig = { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Prebuilt Rule Export Integration Tests - Customization enabled - ESS Env', + }, + }; + + testConfig.kbnTestServer.serverArgs = testConfig.kbnTestServer.serverArgs.map((arg: string) => { + // Override the default value of `--xpack.securitySolution.enableExperimental` to enable the prebuilt rules customization feature + if (arg.includes('--xpack.securitySolution.enableExperimental')) { + return `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`; + } + return arg; + }); + + return testConfig; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/configs/serverless_essentials_tier.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/configs/serverless_essentials_tier.config.ts new file mode 100644 index 000000000000..730ccf0269a9 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/configs/serverless_essentials_tier.config.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../../../config/serverless/config.base.essentials'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Prebuilt Rule Export Integration Tests - Customization enabled - Serverless Env', + }, + kbnTestServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`, + ], +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/export_prebuilt_rules_feature_enabled.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/export_prebuilt_rules_feature_enabled.ts new file mode 100644 index 000000000000..dd06a1a6ec41 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/export_prebuilt_rules_feature_enabled.ts @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { BulkActionTypeEnum } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { + binaryToString, + createPrebuiltRuleAssetSavedObjects, + createRuleAssetSavedObject, + deleteAllPrebuiltRuleAssets, + installPrebuiltRules, +} from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const securitySolutionApi = getService('securitySolutionApi'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI Prebuilt rule export', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + it("Export API - exports prebuilt all rules if rule_id's are not specified", async () => { + const ruleId = 'prebuilt-rule-1'; + const ruleAsset = createRuleAssetSavedObject({ rule_id: ruleId, version: 1 }); + await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]); + await installPrebuiltRules(es, supertest); + + const { body } = await securitySolutionApi + .exportRules({ query: {}, body: null }) + .expect(200) + .parse(binaryToString); + + const [ruleJson, exportDetailsJson] = body.toString().split(/\n/); + + expect(JSON.parse(ruleJson)).toMatchObject({ + rule_id: ruleId, + rule_source: { + type: 'external', + is_customized: false, + }, + }); + + expect(JSON.parse(exportDetailsJson)).toMatchObject({ + exported_rules_count: 1, + missing_rules: [], + }); + }); + + it('Export API - exports specified prebuilt rules', async () => { + const ruleId = 'prebuilt-rule-1'; + const ruleAsset = createRuleAssetSavedObject({ rule_id: ruleId, version: 1 }); + await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]); + await installPrebuiltRules(es, supertest); + + const { body } = await securitySolutionApi + .exportRules({ + query: {}, + body: { + objects: [{ rule_id: ruleId }], + }, + }) + .expect(200) + .parse(binaryToString); + + const [ruleJson, exportDetailsJson] = body.toString().split(/\n/); + + expect(JSON.parse(ruleJson)).toMatchObject({ + rule_id: ruleId, + rule_source: { + type: 'external', + is_customized: false, + }, + }); + + expect(JSON.parse(exportDetailsJson)).toMatchObject({ + exported_rules_count: 1, + missing_rules: [], + }); + }); + + it('Bulk actions export API - exports prebuilt rules', async () => { + const ruleAsset = createRuleAssetSavedObject({ rule_id: 'prebuilt-rule-1', version: 1 }); + await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]); + await installPrebuiltRules(es, supertest); + + const findResponse = await securitySolutionApi.findRules({ query: {} }); + const installedRule = findResponse.body.data[0]; + + const { body } = await securitySolutionApi + .performRulesBulkAction({ + query: {}, + body: { action: BulkActionTypeEnum.export, ids: [installedRule.id] }, + }) + .expect(200) + .parse(binaryToString); + + const [ruleJson, exportDetailsJson] = body.toString().split(/\n/); + + expect(JSON.parse(ruleJson)).toMatchObject({ + id: installedRule.id, + rule_source: { + type: 'external', + is_customized: false, + }, + }); + + expect(JSON.parse(exportDetailsJson)).toMatchObject({ + missing_rules: [], + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/index.ts new file mode 100644 index 000000000000..fdc218eed10d --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/export_prebuilt_rules/feature_enabled/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Rules Management - Prebuilt rule export', function () { + loadTestFile(require.resolve('./export_prebuilt_rules_feature_enabled')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/ess_basic_license.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/ess_basic_license.config.ts new file mode 100644 index 000000000000..0acf5f559a07 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/ess_basic_license.config.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../../../config/ess/config.base.basic') + ); + + const testConfig = { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing customized prebuilt rules - Customization enabled - ESS Env', + }, + }; + + testConfig.kbnTestServer.serverArgs = testConfig.kbnTestServer.serverArgs.map((arg: string) => { + // Override the default value of `--xpack.securitySolution.enableExperimental` to enable the prebuilt rules customization feature + if (arg.includes('--xpack.securitySolution.enableExperimental')) { + return `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`; + } + return arg; + }); + + return testConfig; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts new file mode 100644 index 000000000000..c4e645f80486 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../../../config/ess/config.base.basic') + ); + + const testConfig = { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing customized prebuilt rules - Customization disabled - ESS Env', + }, + }; + + return testConfig; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/serverless_essentials_tier.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/serverless_essentials_tier.config.ts new file mode 100644 index 000000000000..c9dd717d27aa --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/serverless_essentials_tier.config.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../../../config/serverless/config.base.essentials'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing customized prebuilt rules - Customization enabled - Serverless Env', + }, + kbnTestServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`, + ], +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts new file mode 100644 index 000000000000..2d323853ec76 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing customized prebuilt rules - Customization disabled - Serverless Env', + }, + kbnTestServerArgs: [], +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/index.ts new file mode 100644 index 000000000000..413f80d2f76d --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Rules Management - Rule Import API - Customized prebuilt rules', function () { + loadTestFile(require.resolve('./not_allowed_importing_customized_prebuilt_rules')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/not_allowed_importing_customized_prebuilt_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/not_allowed_importing_customized_prebuilt_rules.ts new file mode 100644 index 000000000000..7d4b6c09a712 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_disabled/not_allowed_importing_customized_prebuilt_rules.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { deleteAllPrebuiltRuleAssets, getCustomQueryRuleParams } from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; +import { combineToNdJson } from '../../../../utils/combine_to_ndjson'; +import { createPrebuiltRuleAssetSavedObjects, createRuleAssetSavedObject } from '../../../../utils'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const securitySolutionApi = getService('securitySolutionApi'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI Prebuilt rule import', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + it(`does NOT import customized prebuilt rules when rule customization is disabled`, async () => { + const ruleId = 'prebuilt-rule-to-be-customized'; + const ruleParams = getCustomQueryRuleParams({ + rule_id: ruleId, + // @ts-expect-error the API supports this param, but we only need it in {@link RuleToImport} + immutable: true, + rule_source: { type: 'external', is_customized: false }, + version: 1, + }); + const ruleAsset = createRuleAssetSavedObject(ruleParams); + + await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]); + + // Customizing the rule before importing + const ndjson = combineToNdJson({ ...ruleParams, name: 'My customized rule' }); + + const { body } = await securitySolutionApi + .importRules({ query: {} }) + .attach('file', Buffer.from(ndjson), 'rules.ndjson') + .expect(200); + + expect(body).toMatchObject({ + success: false, + errors: [ + { + rule_id: 'prebuilt-rule-to-be-customized', + error: { + status_code: 400, + message: expect.stringContaining('rule_id: prebuilt-rule-to-be-customized]'), + }, + }, + ], + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/allowed_importing_customized_prebuilt_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/allowed_importing_customized_prebuilt_rules.ts new file mode 100644 index 000000000000..6f71abc686d1 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/allowed_importing_customized_prebuilt_rules.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { + createPrebuiltRuleAssetSavedObjects, + createRuleAssetSavedObject, + deleteAllPrebuiltRuleAssets, + getCustomQueryRuleParams, +} from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; +import { combineToNdJson } from '../../../../utils/combine_to_ndjson'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const securitySolutionApi = getService('securitySolutionApi'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI Prebuilt rule import', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + it(`imports customized prebuilt rules`, async () => { + const ruleId = 'prebuilt-rule-to-be-customized'; + const ruleParams = getCustomQueryRuleParams({ + rule_id: ruleId, + // @ts-expect-error the API supports this param, but we only need it in {@link RuleToImport} + immutable: true, + rule_source: { type: 'external', is_customized: false }, + version: 1, + }); + const ruleAsset = createRuleAssetSavedObject(ruleParams); + + await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]); + + // Customizing the rule before importing + const ndjson = combineToNdJson({ ...ruleParams, name: 'My customized rule' }); + + const { body } = await securitySolutionApi + .importRules({ query: {} }) + .attach('file', Buffer.from(ndjson), 'rules.ndjson') + .expect(200); + + expect(body).toMatchObject({ + success: true, + errors: [], + }); + + const { body: importedRule } = await securitySolutionApi + .readRule({ + query: { rule_id: ruleId }, + }) + .expect(200); + + expect(importedRule).toMatchObject({ + ...ruleParams, + name: 'My customized rule', + rule_source: { + type: 'external', + is_customized: true, + }, + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/configs/ess_enterprise_license.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/configs/ess_enterprise_license.config.ts new file mode 100644 index 000000000000..762a2dc673c1 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/configs/ess_enterprise_license.config.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../../../config/ess/config.base.trial') + ); + + const testConfig = { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing customized prebuilt rules - Customization enabled - ESS Env', + }, + }; + + testConfig.kbnTestServer.serverArgs = testConfig.kbnTestServer.serverArgs.map((arg: string) => { + // Override the default value of `--xpack.securitySolution.enableExperimental` to enable the prebuilt rules customization feature + if (arg.includes('--xpack.securitySolution.enableExperimental')) { + return `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`; + } + return arg; + }); + + return testConfig; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/configs/serverless_complete_tier.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/configs/serverless_complete_tier.config.ts new file mode 100644 index 000000000000..a14e096f3af3 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/configs/serverless_complete_tier.config.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing customized prebuilt rules - Customization disabled - Serverless Env', + }, + kbnTestServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`, + ], +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/index.ts new file mode 100644 index 000000000000..66752a09e225 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_customized_prebuilt_rules/feature_enabled/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Rules Management - Rule Import API - Customized prebuilt rules', function () { + loadTestFile(require.resolve('./allowed_importing_customized_prebuilt_rules')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts new file mode 100644 index 000000000000..e1a7d608d846 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/configs/ess_feature_flag_disabled.config.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../../../config/ess/config.base.trial') + ); + + const testConfig = { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing non-customized prebuilt rules - Customization disabled - ESS Env', + }, + }; + + return testConfig; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts new file mode 100644 index 000000000000..3b112b8c0807 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/configs/serverless_feature_flag_disabled.config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing non-customized prebuilt rules - Customization disabled - Serverless Env', + }, + kbnTestServerArgs: [], +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/index.ts new file mode 100644 index 000000000000..863a54c1b777 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Rules Management - Rule Import API - Non-customized prebuilt rules', function () { + loadTestFile(require.resolve('./not_allowed_importing_non_customized_prebuilt_rules')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/not_allowed_importing_non_customized_prebuilt_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/not_allowed_importing_non_customized_prebuilt_rules.ts new file mode 100644 index 000000000000..dcbe44f784e8 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_disabled/not_allowed_importing_non_customized_prebuilt_rules.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { deleteAllPrebuiltRuleAssets, getCustomQueryRuleParams } from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; +import { combineToNdJson } from '../../../../utils/combine_to_ndjson'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const securitySolutionApi = getService('securitySolutionApi'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI Prebuilt rule import', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + it(`does NOT allow importing non-customized prebuilt rules`, async () => { + const ruleToImport = getCustomQueryRuleParams({ + rule_id: 'non-customized-prebuilt-rule', + // @ts-expect-error the API supports this param, but we only need it in {@link RuleToImport} + immutable: true, + rule_source: { type: 'external', is_customized: false }, + }); + const ndjson = combineToNdJson(ruleToImport); + + const { body } = await securitySolutionApi + .importRules({ query: {} }) + .attach('file', Buffer.from(ndjson), 'rules.ndjson') + .expect(200); + + expect(body).toMatchObject({ + success: false, + errors: [ + { + rule_id: 'non-customized-prebuilt-rule', + error: { + status_code: 400, + message: + 'Importing prebuilt rules is not supported. To import this rule as a custom rule, first duplicate the rule and then export it. [rule_id: non-customized-prebuilt-rule]', + }, + }, + ], + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/allowed_importing_non_customized_prebuilt_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/allowed_importing_non_customized_prebuilt_rules.ts new file mode 100644 index 000000000000..7dd9643cdd18 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/allowed_importing_non_customized_prebuilt_rules.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { + createPrebuiltRuleAssetSavedObjects, + createRuleAssetSavedObject, + deleteAllPrebuiltRuleAssets, + getCustomQueryRuleParams, +} from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; +import { combineToNdJson } from '../../../../utils/combine_to_ndjson'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const securitySolutionApi = getService('securitySolutionApi'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI Import - Customization Enabled', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + it(`imports non-customized prebuilt rules`, async () => { + const ruleId = 'prebuilt-rule'; + const ruleParams = getCustomQueryRuleParams({ + rule_id: ruleId, + // @ts-expect-error the API supports this param, but we only need it in {@link RuleToImport} + immutable: true, + rule_source: { type: 'external', is_customized: false }, + version: 1, + }); + const ruleAsset = createRuleAssetSavedObject(ruleParams); + + await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]); + + const ndjson = combineToNdJson(ruleParams); + + const { body } = await securitySolutionApi + .importRules({ query: {} }) + .attach('file', Buffer.from(ndjson), 'rules.ndjson') + .expect(200); + + expect(body).toMatchObject({ + success: true, + errors: [], + }); + + const { body: importedRule } = await securitySolutionApi + .readRule({ + query: { rule_id: ruleId }, + }) + .expect(200); + + expect(importedRule).toMatchObject(ruleParams); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/configs/ess_basic_license.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/configs/ess_basic_license.config.ts new file mode 100644 index 000000000000..e5013e2fd46c --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/configs/ess_basic_license.config.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../../../config/ess/config.base.basic') + ); + + const testConfig = { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing non-customized prebuilt rules - ESS Env', + }, + }; + + testConfig.kbnTestServer.serverArgs = testConfig.kbnTestServer.serverArgs.map((arg: string) => { + // Override the default value of `--xpack.securitySolution.enableExperimental` to enable the prebuilt rules customization feature + if (arg.includes('--xpack.securitySolution.enableExperimental')) { + return `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`; + } + return arg; + }); + + return testConfig; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/configs/serverless_essentials_tier.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/configs/serverless_essentials_tier.config.ts new file mode 100644 index 000000000000..24f23cb56fe0 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/configs/serverless_essentials_tier.config.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../../../config/serverless/config.base.essentials'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: + 'Rules Management - Rule Import Integration Tests - Importing non-customized prebuilt rules - Serverless Env', + }, + kbnTestServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`, + ], +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/index.ts new file mode 100644 index 000000000000..22cd4aaeda8c --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/import_non_customized_prebuilt_rules/feature_enabled/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Rules Management - Rule Import API - Non-customized prebuilt rules', function () { + loadTestFile(require.resolve('./allowed_importing_non_customized_prebuilt_rules')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_rules.ts index 112c14a3c792..b9ed8c3e0ac3 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_rules.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_rules.ts @@ -1625,36 +1625,6 @@ export default ({ getService }: FtrProviderContext): void => { describe('supporting prebuilt rule customization', () => { describe('compatibility with prebuilt rule fields', () => { - it('rejects rules with "immutable: true" when the feature flag is disabled', async () => { - const rule = getCustomQueryRuleParams({ - rule_id: 'rule-immutable', - // @ts-expect-error the API supports this param, but we only need it in {@link RuleToImport} - immutable: true, - }); - const ndjson = combineToNdJson(rule); - - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_IMPORT_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .attach('file', Buffer.from(ndjson), 'rules.ndjson') - .expect(200); - - expect(body).toMatchObject({ - success: false, - errors: [ - { - rule_id: 'rule-immutable', - error: { - status_code: 400, - message: - 'Importing prebuilt rules is not supported. To import this rule as a custom rule, first duplicate the rule and then export it. [rule_id: rule-immutable]', - }, - }, - ], - }); - }); - it('imports custom rules alongside prebuilt rules when feature flag is disabled', async () => { const ndjson = combineToNdJson( getCustomQueryRuleParams({