diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index 8e51ac05f833a..5c8d70432251e 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -45,13 +45,44 @@ "deprecated": false, "trackAdoption": false, "children": [ + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.kibanaBranch", + "type": "string", + "tags": [], + "label": "kibanaBranch", + "description": [ + "\nThe current Kibana branch. e.g. 'main'" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "securitySolution", "id": "def-public.Plugin.kibanaVersion", "type": "string", "tags": [], "label": "kibanaVersion", - "description": [], + "description": [ + "\nThe current Kibana version. e.g. '8.0.0' or '8.0.0-SNAPSHOT'" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.prebuiltRulesPackageVersion", + "type": "string", + "tags": [], + "label": "prebuiltRulesPackageVersion", + "description": [ + "\nFor internal use. Specify which version of the Detection Rules fleet package to install\nwhen upgrading rules. If not provided, the latest compatible package will be installed,\nor if running from a dev environment or -SNAPSHOT build, the latest pre-release package\nwill be used (if fleet is available or not within an airgapped environment).\n\nNote: This is for `upgrade only`, which occurs by means of the `useUpgradeSecurityPackages`\nhook when navigating to a Security Solution page. The package version specified in\n`fleet_packages.json` in project root will always be installed first on Kibana start if\nthe package is not already installed." + ], + "signature": [ + "string | undefined" + ], "path": "x-pack/plugins/security_solution/public/plugin.tsx", "deprecated": false, "trackAdoption": false @@ -2007,7 +2038,7 @@ "label": "ConfigType", "description": [], "signature": [ - "Readonly<{} & { signalsIndex: string; maxRuleImportExportSize: number; maxRuleImportPayloadBytes: number; maxTimelineImportExportSize: number; maxTimelineImportPayloadBytes: number; alertMergeStrategy: \"allFields\" | \"missingFields\" | \"noFields\"; alertIgnoreFields: string[]; enableExperimental: string[]; packagerTaskInterval: string; }> & { experimentalFeatures: ", + "Readonly<{ prebuiltRulesPackageVersion?: string | undefined; } & { signalsIndex: string; maxRuleImportExportSize: number; maxRuleImportPayloadBytes: number; maxTimelineImportExportSize: number; maxTimelineImportPayloadBytes: number; alertMergeStrategy: \"allFields\" | \"missingFields\" | \"noFields\"; alertIgnoreFields: string[]; enableExperimental: string[]; packagerTaskInterval: string; }> & { experimentalFeatures: ", "ExperimentalFeatures", "; }" ], diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index fb9d774afca33..3dd7644fcda20 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -21,7 +21,7 @@ Contact [Security solution](https://github.com/orgs/elastic/teams/security-solut | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 113 | 0 | 76 | 29 | +| 115 | 0 | 75 | 29 | ## Client diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index c7262af593189..9c5f2511f1617 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -394,6 +394,7 @@ kibana_vars=( xpack.securitySolution.maxTimelineImportExportSize xpack.securitySolution.maxTimelineImportPayloadBytes xpack.securitySolution.packagerTaskInterval + xpack.securitySolution.prebuiltRulesPackageVersion xpack.spaces.maxSpaces xpack.task_manager.max_attempts xpack.task_manager.max_poll_inactivity_cycles diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 5c51d00f5afd1..a13d19e5246eb 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -218,6 +218,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.security.sameSiteCookies (alternatives)', 'xpack.security.showInsecureClusterWarning (boolean)', 'xpack.securitySolution.enableExperimental (array)', + 'xpack.securitySolution.prebuiltRulesPackageVersion (string)', 'xpack.snapshot_restore.slm_ui.enabled (boolean)', 'xpack.snapshot_restore.ui.enabled (boolean)', 'xpack.trigger_actions_ui.enableExperimental (array)', diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_secuirty_packages.test.tsx b/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_secuirty_packages.test.tsx index f40f1dd0fecc0..0352dd03bbcff 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_secuirty_packages.test.tsx +++ b/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_secuirty_packages.test.tsx @@ -6,7 +6,7 @@ */ import React, { memo } from 'react'; -import { useKibana } from '../lib/kibana'; +import { KibanaServices, useKibana } from '../lib/kibana'; import type { RenderHookResult } from '@testing-library/react-hooks'; import { renderHook as _renderHook } from '@testing-library/react-hooks'; import { useUpgradeSecurityPackages } from './use_upgrade_security_packages'; @@ -23,8 +23,11 @@ jest.mock('../components/user_privileges', () => { }); jest.mock('../lib/kibana'); -// FLAKY: https://github.com/elastic/kibana/issues/112910 -describe.skip('When using the `useUpgradeSecurityPackages()` hook', () => { +describe('When using the `useUpgradeSecurityPackages()` hook', () => { + const mockGetPrebuiltRulesPackageVersion = + KibanaServices.getPrebuiltRulesPackageVersion as jest.Mock; + const mockGetKibanaVersion = KibanaServices.getKibanaVersion as jest.Mock; + const mockGetKibanaBranch = KibanaServices.getKibanaBranch as jest.Mock; let renderResult: RenderHookResult; let renderHook: () => RenderHookResult; let kibana: ReturnType; @@ -43,6 +46,7 @@ describe.skip('When using the `useUpgradeSecurityPackages()` hook', () => { }); afterEach(() => { + jest.clearAllMocks(); if (renderResult) { renderResult.unmount(); } @@ -65,4 +69,104 @@ describe.skip('When using the `useUpgradeSecurityPackages()` hook', () => { }) ); }); + + it('should send upgrade request with prerelease:false if branch is not `main` and build does not include `-SNAPSHOT`', async () => { + mockGetKibanaVersion.mockReturnValue('8.0.0'); + mockGetKibanaBranch.mockReturnValue('release'); + + renderHook(); + + await renderResult.waitFor( + () => (kibana.services.http.post as jest.Mock).mock.calls.length > 0 + ); + + expect(kibana.services.http.post).toHaveBeenCalledWith( + `${epmRouteService.getBulkInstallPath()}`, + expect.objectContaining({ + body: '{"packages":["endpoint","security_detection_engine"]}', + query: expect.objectContaining({ prerelease: false }), + }) + ); + }); + + it('should send upgrade request with prerelease:true if branch is `main` AND build includes `-SNAPSHOT`', async () => { + mockGetKibanaVersion.mockReturnValue('8.0.0-SNAPSHOT'); + mockGetKibanaBranch.mockReturnValue('main'); + + renderHook(); + + await renderResult.waitFor( + () => (kibana.services.http.post as jest.Mock).mock.calls.length > 0 + ); + + expect(kibana.services.http.post).toHaveBeenCalledWith( + `${epmRouteService.getBulkInstallPath()}`, + expect.objectContaining({ + body: '{"packages":["endpoint","security_detection_engine"]}', + query: expect.objectContaining({ prerelease: true }), + }) + ); + }); + + it('should send upgrade request with prerelease:true if branch is `release` and build includes `-SNAPSHOT`', async () => { + mockGetKibanaVersion.mockReturnValue('8.0.0-SNAPSHOT'); + mockGetKibanaBranch.mockReturnValue('release'); + + renderHook(); + + await renderResult.waitFor( + () => (kibana.services.http.post as jest.Mock).mock.calls.length > 0 + ); + + expect(kibana.services.http.post).toHaveBeenCalledWith( + `${epmRouteService.getBulkInstallPath()}`, + expect.objectContaining({ + body: '{"packages":["endpoint","security_detection_engine"]}', + query: expect.objectContaining({ prerelease: true }), + }) + ); + }); + + it('should send upgrade request with prerelease:true if branch is `main` and build does not include `-SNAPSHOT`', async () => { + mockGetKibanaVersion.mockReturnValue('8.0.0'); + mockGetKibanaBranch.mockReturnValue('main'); + + renderHook(); + + await renderResult.waitFor( + () => (kibana.services.http.post as jest.Mock).mock.calls.length > 0 + ); + + expect(kibana.services.http.post).toHaveBeenCalledWith( + `${epmRouteService.getBulkInstallPath()}`, + expect.objectContaining({ + body: '{"packages":["endpoint","security_detection_engine"]}', + query: expect.objectContaining({ prerelease: true }), + }) + ); + }); + + it('should send separate upgrade requests if prebuiltRulesPackageVersion is provided', async () => { + mockGetPrebuiltRulesPackageVersion.mockReturnValue('8.2.1'); + + renderHook(); + + await renderResult.waitFor( + () => (kibana.services.http.post as jest.Mock).mock.calls.length > 0 + ); + + expect(kibana.services.http.post).toHaveBeenNthCalledWith( + 1, + `${epmRouteService.getInstallPath('security_detection_engine', '8.2.1')}`, + expect.objectContaining({ query: { prerelease: true } }) + ); + expect(kibana.services.http.post).toHaveBeenNthCalledWith( + 2, + `${epmRouteService.getBulkInstallPath()}`, + expect.objectContaining({ + body: expect.stringContaining('endpoint'), + query: expect.objectContaining({ prerelease: true }), + }) + ); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_security_packages.ts b/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_security_packages.ts index 848f1458502ca..1354770b7384d 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_security_packages.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_security_packages.ts @@ -9,7 +9,8 @@ import { useEffect } from 'react'; import type { HttpFetchOptions, HttpStart } from '@kbn/core/public'; import type { BulkInstallPackagesResponse } from '@kbn/fleet-plugin/common'; import { epmRouteService } from '@kbn/fleet-plugin/common'; -import { useKibana } from '../lib/kibana'; +import type { InstallPackageResponse } from '@kbn/fleet-plugin/common/types'; +import { KibanaServices, useKibana } from '../lib/kibana'; import { useUserPrivileges } from '../components/user_privileges'; /** @@ -17,17 +18,44 @@ import { useUserPrivileges } from '../components/user_privileges'; * * @param http an http client for sending the request * @param options an object containing options for the request + * @param prebuiltRulesPackageVersion specific version of the prebuilt rules package to install */ const sendUpgradeSecurityPackages = async ( http: HttpStart, - options: HttpFetchOptions = {} -): Promise => { - return http.post(epmRouteService.getBulkInstallPath(), { - ...options, - body: JSON.stringify({ - packages: ['endpoint', 'security_detection_engine'], - }), - }); + options: HttpFetchOptions = {}, + prebuiltRulesPackageVersion?: string +): Promise => { + const packages = ['endpoint', 'security_detection_engine']; + const requests: Array> = []; + + // If `prebuiltRulesPackageVersion` is provided, try to install that version + // Must be done as two separate requests as bulk API doesn't support versions + if (prebuiltRulesPackageVersion != null) { + packages.splice(packages.indexOf('security_detection_engine'), 1); + requests.push( + http.post( + epmRouteService.getInstallPath('security_detection_engine', prebuiltRulesPackageVersion), + { + ...options, + body: JSON.stringify({ + force: true, + }), + } + ) + ); + } + + // Note: if `prerelease:true` option is provided, endpoint package will also be installed as prerelease + requests.push( + http.post(epmRouteService.getBulkInstallPath(), { + ...options, + body: JSON.stringify({ + packages, + }), + }) + ); + + await Promise.allSettled(requests); }; export const useUpgradeSecurityPackages = () => { @@ -50,8 +78,23 @@ export const useUpgradeSecurityPackages = () => { // Make sure fleet is initialized first await context.services.fleet?.isInitialized(); + // Always install the latest package if in dev env or snapshot build + const isPrerelease = + KibanaServices.getKibanaVersion().includes('-SNAPSHOT') || + KibanaServices.getKibanaBranch() === 'main'; + // ignore the response for now since we aren't notifying the user - await sendUpgradeSecurityPackages(context.services.http, { signal }); + // Note: response would be Promise.allSettled, so must iterate all responses for errors and throw manually + await sendUpgradeSecurityPackages( + context.services.http, + { + query: { + prerelease: isPrerelease, + }, + signal, + }, + KibanaServices.getPrebuiltRulesPackageVersion() + ); } catch (error) { // Ignore Errors, since this should not hinder the user's ability to use the UI diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts index 6b736e3fbb503..2822a48669b32 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts @@ -36,6 +36,8 @@ export const KibanaServices = { }; }), getKibanaVersion: jest.fn(() => '8.0.0'), + getKibanaBranch: jest.fn(() => 'main'), + getPrebuiltRulesPackageVersion: jest.fn(() => undefined), }; export const useKibana = jest.fn().mockReturnValue({ services: { diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/services.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/services.ts index 7b38c7e2a4218..cbd2ddce441ae 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/services.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/services.ts @@ -12,7 +12,9 @@ type GlobalServices = Pick; export class KibanaServices { + private static kibanaBranch?: string; private static kibanaVersion?: string; + private static prebuiltRulesPackageVersion?: string; private static services?: GlobalServices; public static init({ @@ -20,19 +22,20 @@ export class KibanaServices { application, data, unifiedSearch, + kibanaBranch, kibanaVersion, + prebuiltRulesPackageVersion, uiSettings, notifications, - }: GlobalServices & { kibanaVersion: string }) { - this.services = { - application, - data, - http, - uiSettings, - unifiedSearch, - notifications, - }; + }: GlobalServices & { + kibanaBranch: string; + kibanaVersion: string; + prebuiltRulesPackageVersion?: string; + }) { + this.services = { application, data, http, uiSettings, unifiedSearch, notifications }; + this.kibanaBranch = kibanaBranch; this.kibanaVersion = kibanaVersion; + this.prebuiltRulesPackageVersion = prebuiltRulesPackageVersion; } public static get(): GlobalServices { @@ -43,6 +46,14 @@ export class KibanaServices { return this.services; } + public static getKibanaBranch(): string { + if (!this.kibanaBranch) { + this.throwUninitializedError(); + } + + return this.kibanaBranch; + } + public static getKibanaVersion(): string { if (!this.kibanaVersion) { this.throwUninitializedError(); @@ -51,6 +62,10 @@ export class KibanaServices { return this.kibanaVersion; } + public static getPrebuiltRulesPackageVersion(): string | undefined { + return this.prebuiltRulesPackageVersion; + } + private static throwUninitializedError(): never { throw new Error( 'Kibana services not initialized - are you trying to import this module from outside of the SIEM app?' diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx index 2e2cdbdd3eda5..5a9d092ad5097 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx @@ -292,6 +292,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { const globalKibanaServicesParams = { ...startServices, kibanaVersion: '8.0.0', + kibanaBranch: 'main', }; if (jest.isMockFunction(KibanaServices.get)) { diff --git a/x-pack/plugins/security_solution/public/common/types.ts b/x-pack/plugins/security_solution/public/common/types.ts index 8eced13424255..c639975e499a0 100644 --- a/x-pack/plugins/security_solution/public/common/types.ts +++ b/x-pack/plugins/security_solution/public/common/types.ts @@ -18,6 +18,7 @@ export interface ServerApiError { export interface SecuritySolutionUiConfigType { enableExperimental: string[]; + prebuiltRulesPackageVersion?: string; } /** diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index 3e08672939b5c..b7b4fcb051d65 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -61,7 +61,26 @@ import { LazyEndpointCustomAssetsExtension } from './management/pages/policy/vie import type { SecurityAppStore } from './common/store/types'; export class Plugin implements IPlugin { + /** + * The current Kibana branch. e.g. 'main' + */ + readonly kibanaBranch: string; + /** + * The current Kibana version. e.g. '8.0.0' or '8.0.0-SNAPSHOT' + */ readonly kibanaVersion: string; + /** + * For internal use. Specify which version of the Detection Rules fleet package to install + * when upgrading rules. If not provided, the latest compatible package will be installed, + * or if running from a dev environment or -SNAPSHOT build, the latest pre-release package + * will be used (if fleet is available or not within an airgapped environment). + * + * Note: This is for `upgrade only`, which occurs by means of the `useUpgradeSecurityPackages` + * hook when navigating to a Security Solution page. The package version specified in + * `fleet_packages.json` in project root will always be installed first on Kibana start if + * the package is not already installed. + */ + readonly prebuiltRulesPackageVersion?: string; private config: SecuritySolutionUiConfigType; readonly experimentalFeatures: ExperimentalFeatures; @@ -69,6 +88,8 @@ export class Plugin implements IPlugin(); this.experimentalFeatures = parseExperimentalConfigValue(this.config.enableExperimental || []); this.kibanaVersion = initializerContext.env.packageInfo.version; + this.kibanaBranch = initializerContext.env.packageInfo.branch; + this.prebuiltRulesPackageVersion = this.config.prebuiltRulesPackageVersion; } private appUpdater$ = new Subject(); @@ -214,7 +235,13 @@ export class Plugin implements IPlugin { maxTimelineImportPayloadBytes: 10485760, enableExperimental, packagerTaskInterval: '60s', + prebuiltRulesPackageVersion: '', alertMergeStrategy: 'missingFields', alertIgnoreFields: [], diff --git a/x-pack/plugins/security_solution/server/config.ts b/x-pack/plugins/security_solution/server/config.ts index 08683436505e3..5a4d18edda11c 100644 --- a/x-pack/plugins/security_solution/server/config.ts +++ b/x-pack/plugins/security_solution/server/config.ts @@ -109,6 +109,19 @@ export const configSchema = schema.object({ * Artifacts Configuration */ packagerTaskInterval: schema.string({ defaultValue: '60s' }), + + /** + * For internal use. Specify which version of the Detection Rules fleet package to install + * when upgrading rules. If not provided, the latest compatible package will be installed, + * or if running from a dev environment or -SNAPSHOT build, the latest pre-release package + * will be used (if fleet is available or not within an airgapped environment). + * + * Note: This is for `upgrade only`, which occurs by means of the `useUpgradeSecurityPackages` + * hook when navigating to a Security Solution page. The package version specified in + * `fleet_packages.json` in project root will always be installed first on Kibana start if + * the package is not already installed. + */ + prebuiltRulesPackageVersion: schema.maybe(schema.string()), }); export type ConfigSchema = TypeOf; diff --git a/x-pack/plugins/security_solution/server/index.ts b/x-pack/plugins/security_solution/server/index.ts index e167f62afd1e7..cc59610f21124 100644 --- a/x-pack/plugins/security_solution/server/index.ts +++ b/x-pack/plugins/security_solution/server/index.ts @@ -20,6 +20,7 @@ export const plugin = (context: PluginInitializerContext) => { export const config: PluginConfigDescriptor = { exposeToBrowser: { enableExperimental: true, + prebuiltRulesPackageVersion: true, }, schema: configSchema, deprecations: ({ renameFromRoot, unused }) => [ diff --git a/x-pack/test/detection_engine_api_integration/utils/install_detection_rules_package_from_fleet.ts b/x-pack/test/detection_engine_api_integration/utils/install_detection_rules_package_from_fleet.ts new file mode 100644 index 0000000000000..72408d8fd2af1 --- /dev/null +++ b/x-pack/test/detection_engine_api_integration/utils/install_detection_rules_package_from_fleet.ts @@ -0,0 +1,61 @@ +/* + * 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 { epmRouteService } from '@kbn/fleet-plugin/common'; +import { InstallPackageResponse } from '@kbn/fleet-plugin/common/types'; +import type { ToolingLog } from '@kbn/tooling-log'; +import type SuperTest from 'supertest'; + +/** + * Installed the security_detection_engine package via fleet API. Will + * @param supertest The supertest deps + * @param log The tooling logger + * @param version The version to install, e.g. '8.4.1' + * @param overrideExistingPackage Whether or not to force the install + */ +export const installDetectionRulesPackageFromFleet = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + version: string, + overrideExistingPackage: true +): Promise => { + const response = await supertest + .post(epmRouteService.getInstallPath('security_detection_engine', version)) + .set('kbn-xsrf', 'true') + .send({ + force: overrideExistingPackage, + }); + if (response.status !== 200) { + log.error( + `Did not get an expected 200 "ok" when installing 'security_detection_engine' fleet package'. body: ${JSON.stringify( + response.body + )}, status: ${JSON.stringify(response.status)}` + ); + } + return response.body; +}; + +/** + * Returns the `--xpack.securitySolution.prebuiltRulesPackageVersion=8.3.1` setting + * as configured in the kbnServerArgs from the test's config.ts. + * @param kbnServerArgs Kibana server args within scope + */ +export const getPrebuiltRulesPackageVersionFromServerArgs = (kbnServerArgs: string[]): string => { + const re = + /--xpack\.securitySolution\.prebuiltRulesPackageVersion=(?.*)/; + for (const serverArg of kbnServerArgs) { + const match = re.exec(serverArg); + const prebuiltRulesPackageVersion = match?.groups?.prebuiltRulesPackageVersion; + if (prebuiltRulesPackageVersion) { + return prebuiltRulesPackageVersion; + } + } + + throw Error( + 'xpack.securitySolution.prebuiltRulesPackageVersion is not set in the server arguments' + ); +}; diff --git a/x-pack/test/security_solution_cypress/config.ts b/x-pack/test/security_solution_cypress/config.ts index 81d18ce1cab5d..c8048c0b1ba4b 100644 --- a/x-pack/test/security_solution_cypress/config.ts +++ b/x-pack/test/security_solution_cypress/config.ts @@ -52,6 +52,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { // mock cloud to enable the guided onboarding tour in e2e tests '--xpack.cloud.id=test', `--home.disableWelcomeScreen=true`, + // Specify which version of the detection-rules package to install + // `--xpack.securitySolution.prebuiltRulesPackageVersion=8.3.1`, ], }, };