diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index 60b702fa1d8fc..6958ec4530ae8 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -39,6 +39,9 @@ disabled: - x-pack/test/fleet_cypress/config.space_awareness.ts - x-pack/test/fleet_cypress/visual_config.ts + # Default http2 config to use for performance journeys + - x-pack/performance/configs/http2_config.ts + defaultQueue: 'n2-4-spot' enabled: - test/accessibility/config.ts @@ -345,6 +348,7 @@ enabled: - x-pack/test/usage_collection/config.ts - x-pack/performance/journeys_e2e/aiops_log_rate_analysis.ts - x-pack/performance/journeys_e2e/ecommerce_dashboard.ts + - x-pack/performance/journeys_e2e/ecommerce_dashboard_http2.ts - x-pack/performance/journeys_e2e/ecommerce_dashboard_map_only.ts - x-pack/performance/journeys_e2e/flight_dashboard.ts - x-pack/performance/journeys_e2e/login.ts @@ -358,6 +362,7 @@ enabled: - x-pack/performance/journeys_e2e/web_logs_dashboard_esql.ts - x-pack/performance/journeys_e2e/web_logs_dashboard_dataview.ts - x-pack/performance/journeys_e2e/data_stress_test_lens.ts + - x-pack/performance/journeys_e2e/data_stress_test_lens_http2.ts - x-pack/performance/journeys_e2e/ecommerce_dashboard_saved_search_only.ts - x-pack/performance/journeys_e2e/ecommerce_dashboard_tsvb_gauge_only.ts - x-pack/performance/journeys_e2e/dashboard_listing_page.ts diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index cfc4c0564962b..c5132fe51a678 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -237,6 +237,14 @@ you make the necessary updates after you upgrade to 8.15.0. The Uptime app is already hidden from Kibana when there is no recent Heartbeat data, but will be completely removed in 9.0.0. You should migrate to Synthetics as an alternative. For more details, refer to the {observability-guide}/uptime-intro.html[Uptime documentation]. ==== +[discrete] +.<> are deprecated in 8.15.0 and will be removed in a future version. +[%collapsible] +==== +*Details* + +Search sessions are now deprecated and will be removed in a future version. By default, queries that take longer than 10 minutes (the default for the advanced setting `search:timeout`) will be canceled. To allow queries to run longer, consider increasing `search:timeout` or setting it to `0` which will allow queries to continue running as long as a user is waiting on-screen for results. +==== + [float] [[breaking-changes-8.15.0]] === Breaking changes diff --git a/docs/upgrade-notes.asciidoc b/docs/upgrade-notes.asciidoc index 57b97856a3d40..43fb4d5ac66e5 100644 --- a/docs/upgrade-notes.asciidoc +++ b/docs/upgrade-notes.asciidoc @@ -1481,6 +1481,18 @@ The following rule action variables have been deprecated. Use the recommended va For more information, refer to ({kibana-pull}161136[#161136]). ==== +// Discover + +[discrete] +[[deprecation-search-sessions]] +.[Discover] <> are deprecated in 8.15.0 and will be removed in a future version. (8.15) +[%collapsible] +==== +*Details* + +Search sessions are now deprecated and will be removed in a future version. By default, queries that take longer than 10 minutes (the default for the advanced setting `search:timeout`) will be canceled. To allow queries to run longer, consider increasing `search:timeout` or setting it to `0` which will allow queries to continue running as long as a user is waiting on-screen for results. +==== + + // General settings [discrete] diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts index 9cf211315757e..85a6fadcc8f5c 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts @@ -260,7 +260,7 @@ describe('function validation', () => { // date await expectErrors('FROM a_index | EVAL TEST(NOW())', []); await expectErrors('FROM a_index | EVAL TEST(1.)', [ - 'Argument of [test] must be [date], found value [1] type [decimal]', + 'Argument of [test] must be [date], found value [1.] type [decimal]', ]); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index 23508eeedd234..2790a8a14a3b1 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -112,7 +112,7 @@ function validateFunctionLiteralArg( values: { name: astFunction.name, argType: argDef.type as string, - value: typeof actualArg.value === 'number' ? actualArg.value : String(actualArg.value), + value: actualArg.text, givenType: actualArg.literalType, }, locations: actualArg.location, diff --git a/packages/serverless/settings/observability_project/index.ts b/packages/serverless/settings/observability_project/index.ts index f8bb8dbe12542..44f30e4320463 100644 --- a/packages/serverless/settings/observability_project/index.ts +++ b/packages/serverless/settings/observability_project/index.ts @@ -37,5 +37,4 @@ export const OBSERVABILITY_PROJECT_SETTINGS = [ settings.OBSERVABILITY_AI_ASSISTANT_SIMULATED_FUNCTION_CALLING, settings.OBSERVABILITY_AI_ASSISTANT_SEARCH_CONNECTOR_INDEX_PATTERN, settings.OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID, - settings.OBSERVABILITY_SEARCH_EXCLUDED_DATA_TIERS, ]; diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index 406f6e4de5af0..2eaa14bf24eda 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -123,7 +123,7 @@ describe('checking migration metadata changes on all registered SO types', () => "ingest-agent-policies": "5e95e539826a40ad08fd0c1d161da0a4d86ffc6d", "ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d", "ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91", - "ingest-package-policies": "dc2af447c335215be2d6f7b7b8d437d05d6a1188", + "ingest-package-policies": "53a94064674835fdb35e5186233bcd7052eabd22", "ingest_manager_settings": "111a616eb72627c002029c19feb9e6c439a10505", "inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83", "kql-telemetry": "93c1d16c1a0dfca9c8842062cf5ef8f62ae401ad", diff --git a/src/dev/performance/run_performance_cli.ts b/src/dev/performance/run_performance_cli.ts index df6020ba62a34..fd0f4094124ab 100644 --- a/src/dev/performance/run_performance_cli.ts +++ b/src/dev/performance/run_performance_cli.ts @@ -47,6 +47,7 @@ const journeyTargetGroups: JourneyTargetGroups = { maps: ['ecommerce_dashboard_map_only'], ml: ['aiops_log_rate_analysis', 'many_fields_transform', 'tsdb_logs_data_visualizer'], esql: ['many_fields_discover_esql', 'web_logs_dashboard_esql'], + http2: ['data_stress_test_lens_http2', 'ecommerce_dashboard_http2'], }; const readFilesRecursively = (dir: string, callback: Function) => { diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/cumulative_sum.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/cumulative_sum.ts index 07ed7eceb9930..3b470da64c5c2 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/cumulative_sum.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/cumulative_sum.ts @@ -33,7 +33,7 @@ export const convertToCumulativeSumColumns = ( // lens supports cumulative sum for count and sum as quick function // and everything else as formula if (subFunctionMetric.type !== 'count' && pipelineAgg.name !== 'sum') { - const metaValue = Number(meta?.replace(']', '')); + const metaValue = Number(meta?.replace(/\]/g, '')); formula = getPipelineSeriesFormula(metric, metrics, subFunctionMetric, { metaValue, reducedTimeRange, diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts index cd0a3a62a8dd5..a1a42c12a64fa 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts @@ -66,7 +66,7 @@ const convertFormulaScriptForPercentileAggs = ( ) => { variables.forEach((variable) => { const [_, meta] = variable?.field?.split('[') ?? []; - const metaValue = Number(meta?.replace(']', '')); + const metaValue = Number(meta?.replace(/\]/g, '')); if (!metaValue) { return; } @@ -163,7 +163,7 @@ export const convertOtherAggsToFormulaColumn = ( const metric = metrics[metrics.length - 1]; const [fieldId, meta] = metric?.field?.split('[') ?? []; const subFunctionMetric = metrics.find(({ id }) => id === fieldId); - const metaValue = meta ? Number(meta?.replace(']', '')) : undefined; + const metaValue = meta ? Number(meta?.replace(/\]/g, '')) : undefined; if (!subFunctionMetric) { return null; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.ts index 5ac5701eef6c7..e617ef70c5da2 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.ts @@ -235,7 +235,7 @@ const convertMovingAvgOrDerivativeToColumns = ( if (!pipelineAgg) { return null; } - const metaValue = Number(meta?.replace(']', '')); + const metaValue = Number(meta?.replace(/\]/g, '')); const subMetricField = subFunctionMetric.field; const [nestedFieldId, _] = subMetricField?.split('[') ?? []; // support nested aggs with formula diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.ts index 22cd37255b59e..813f28d4b6924 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.ts @@ -14,7 +14,7 @@ import { addAdditionalArgs } from '.'; import { AdditionalArgs } from '../../types'; const escapeQuotes = (str: string) => { - return str?.replace(/'/g, "\\'"); + return str?.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); }; const constructFilterRationFormula = ( diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts index da5e9e8cffb35..14e1b66df1e26 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts @@ -113,7 +113,7 @@ export const getFormulaEquivalent = ( } return getPipelineSeriesFormula(currentMetric, metrics, subFunctionMetric, { - metaValue: nestedMetaValue ? Number(nestedMetaValue?.replace(']', '')) : undefined, + metaValue: nestedMetaValue ? Number(nestedMetaValue?.replace(/\]/g, '')) : undefined, reducedTimeRange, timeShift, }); diff --git a/x-pack/packages/ml/data_grid/hooks/use_data_grid.tsx b/x-pack/packages/ml/data_grid/hooks/use_data_grid.tsx index dc87c68cc9b7c..f5ddb45642985 100644 --- a/x-pack/packages/ml/data_grid/hooks/use_data_grid.tsx +++ b/x-pack/packages/ml/data_grid/hooks/use_data_grid.tsx @@ -14,7 +14,7 @@ import { ES_CLIENT_TOTAL_HITS_RELATION } from '@kbn/ml-query-utils'; import { INDEX_STATUS } from '../lib/common'; import type { ChartData } from '../lib/field_histograms'; import { ColumnChart } from '../components/column_chart'; -import { COLUMN_CHART_DEFAULT_VISIBILITY_ROWS_THRESHOLD, INIT_MAX_COLUMNS } from '../lib/common'; +import { MAX_ROW_COUNT, INIT_MAX_COLUMNS } from '../lib/common'; import type { ChartsVisible, ColumnId, @@ -62,6 +62,11 @@ export const useDataGrid = ( const { rowCount, rowCountRelation } = rowCountInfo; + const setLimitedRowCountInfo = useCallback((info: RowCountInfo) => { + const limitedRowCount = Math.min(info.rowCount, MAX_ROW_COUNT); + setRowCountInfo({ rowCount: limitedRowCount, rowCountRelation: info.rowCountRelation }); + }, []); + const toggleChartVisibility = () => { if (chartsVisible !== undefined) { setChartsVisible(!chartsVisible); @@ -161,10 +166,7 @@ export const useDataGrid = ( // we decide whether to show or hide the charts by default. useEffect(() => { if (chartsVisible === undefined && rowCount > 0 && rowCountRelation !== undefined) { - setChartsVisible( - rowCount <= COLUMN_CHART_DEFAULT_VISIBILITY_ROWS_THRESHOLD && - rowCountRelation !== ES_CLIENT_TOTAL_HITS_RELATION.GTE - ); + setChartsVisible(rowCountRelation !== ES_CLIENT_TOTAL_HITS_RELATION.GTE); } }, [chartsVisible, rowCount, rowCountRelation]); @@ -189,7 +191,7 @@ export const useDataGrid = ( setErrorMessage, setNoDataMessage, setPagination, - setRowCountInfo, + setRowCountInfo: setLimitedRowCountInfo, setSortingColumns, setStatus, setTableItems, diff --git a/x-pack/packages/ml/data_grid/lib/common.ts b/x-pack/packages/ml/data_grid/lib/common.ts index 82c6cfa618174..bb20c8465dd4a 100644 --- a/x-pack/packages/ml/data_grid/lib/common.ts +++ b/x-pack/packages/ml/data_grid/lib/common.ts @@ -42,9 +42,9 @@ import type { DataGridItem, IndexPagination, RenderCellValue } from './types'; export const INIT_MAX_COLUMNS = 10; /** - * The default threshold value for the number of rows at which the column chart visibility is set to true. + * The default maximum row count value, set to 10000 due to ES limitations. */ -export const COLUMN_CHART_DEFAULT_VISIBILITY_ROWS_THRESHOLD = 10000; +export const MAX_ROW_COUNT = 10000; /** * Enum for index status diff --git a/x-pack/packages/ml/data_grid/lib/types.ts b/x-pack/packages/ml/data_grid/lib/types.ts index 4475d8572bcc8..a652e92d4c522 100644 --- a/x-pack/packages/ml/data_grid/lib/types.ts +++ b/x-pack/packages/ml/data_grid/lib/types.ts @@ -250,7 +250,7 @@ export interface UseDataGridReturnType { /** * Setter function for the row count info. */ - setRowCountInfo: Dispatch>; + setRowCountInfo: (info: RowCountInfo) => void; /** * Setter function for the sorting columns. */ diff --git a/x-pack/performance/configs/http2_config.ts b/x-pack/performance/configs/http2_config.ts new file mode 100644 index 0000000000000..d9d06b7c15ada --- /dev/null +++ b/x-pack/performance/configs/http2_config.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrConfigProviderContext } from '@kbn/test'; +import { configureHTTP2 } from '@kbn/test-suites-src/common/configure_http2'; + +// eslint-disable-next-line import/no-default-export +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const xpackFunctionalConfig = await readConfigFile( + require.resolve('@kbn/test-suites-xpack/functional/config.base') + ); + + return configureHTTP2({ + ...xpackFunctionalConfig.getAll(), + }); +} diff --git a/x-pack/performance/journeys_e2e/data_stress_test_lens_http2.ts b/x-pack/performance/journeys_e2e/data_stress_test_lens_http2.ts new file mode 100644 index 0000000000000..9f02fe7ba874a --- /dev/null +++ b/x-pack/performance/journeys_e2e/data_stress_test_lens_http2.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Journey } from '@kbn/journeys'; + +export const journey = new Journey({ + kbnArchives: ['test/functional/fixtures/kbn_archiver/stress_test'], + esArchives: ['test/functional/fixtures/es_archiver/stress_test'], + ftrConfigPath: 'x-pack/performance/configs/http2_config.ts', +}).step('Go to dashboard', async ({ page, kbnUrl, kibanaServer, kibanaPage }) => { + await kibanaServer.uiSettings.update({ 'histogram:maxBars': 100 }); + await page.goto(kbnUrl.get(`/app/dashboards#/view/92b143a0-2e9c-11ed-b1b6-a504560b392c`)); + await kibanaPage.waitForVisualizations({ count: 1 }); +}); diff --git a/x-pack/performance/journeys_e2e/ecommerce_dashboard_http2.ts b/x-pack/performance/journeys_e2e/ecommerce_dashboard_http2.ts new file mode 100644 index 0000000000000..57e11d461c00a --- /dev/null +++ b/x-pack/performance/journeys_e2e/ecommerce_dashboard_http2.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 { Journey } from '@kbn/journeys'; +import { subj } from '@kbn/test-subj-selector'; + +export const journey = new Journey({ + esArchives: ['x-pack/performance/es_archives/sample_data_ecommerce'], + kbnArchives: ['x-pack/performance/kbn_archives/ecommerce_no_map_dashboard'], + ftrConfigPath: 'x-pack/performance/configs/http2_config.ts', +}) + + .step('Go to Dashboards Page', async ({ page, kbnUrl, kibanaPage }) => { + await page.goto(kbnUrl.get(`/app/dashboards`)); + await kibanaPage.waitForListViewTable(); + }) + + .step('Go to Ecommerce Dashboard', async ({ page, kibanaPage }) => { + await page.click(subj('dashboardListingTitleLink-[eCommerce]-Revenue-Dashboard')); + await kibanaPage.waitForVisualizations({ count: 13 }); + }); diff --git a/x-pack/performance/tsconfig.json b/x-pack/performance/tsconfig.json index 5c00a3b2895d8..6718cd64c9640 100644 --- a/x-pack/performance/tsconfig.json +++ b/x-pack/performance/tsconfig.json @@ -22,5 +22,6 @@ "@kbn/expect", "@kbn/dev-utils", "@kbn/apm-synthtrace-client", + "@kbn/test-suites-src", ] } diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index d1dbeb9d35b64..ffb9381f8b30c 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -101,7 +101,6 @@ import { migratePackagePolicySetRequiresRootToV8150, } from './migrations/to_v8_15_0'; import { backfillAgentPolicyToV4 } from './model_versions/agent_policy_v4'; -import { packagePolicyV15AdvancedFieldsForEndpointV816 } from './model_versions/security_solution/v15_advanced_package_policy_fields'; /* * Saved object types and mappings @@ -751,14 +750,6 @@ export const getSavedObjectTypes = ( }, ], }, - '15': { - changes: [ - { - type: 'data_backfill', - backfillFn: packagePolicyV15AdvancedFieldsForEndpointV816, - }, - ], - }, }, migrations: { '7.10.0': migratePackagePolicyToV7100, diff --git a/x-pack/plugins/fleet/server/saved_objects/model_versions/security_solution/v15_advanced_package_policy_fields.test.ts b/x-pack/plugins/fleet/server/saved_objects/model_versions/security_solution/v15_advanced_package_policy_fields.test.ts deleted file mode 100644 index 795c05966f53b..0000000000000 --- a/x-pack/plugins/fleet/server/saved_objects/model_versions/security_solution/v15_advanced_package_policy_fields.test.ts +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { SavedObject } from '@kbn/core-saved-objects-api-server'; -import type { ModelVersionTestMigrator } from '@kbn/core-test-helpers-model-versions'; -import { createModelVersionTestMigrator } from '@kbn/core-test-helpers-model-versions'; -import { set } from '@kbn/safer-lodash-set'; - -import { getSavedObjectTypes } from '../..'; - -import type { PackagePolicy } from '../../../../common'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../common'; - -describe('Defend integration advanced policy fields v8.16.0', () => { - const TARGET_MODEL_VERSION = 15; - - let migrator: ModelVersionTestMigrator; - let policyConfigSO: SavedObject; - - beforeEach(() => { - migrator = createModelVersionTestMigrator({ - type: getSavedObjectTypes()[PACKAGE_POLICY_SAVED_OBJECT_TYPE], - }); - - policyConfigSO = { - id: 'mock-saved-object-id', - attributes: { - name: 'Some Policy Name', - package: { - name: 'endpoint', - title: '', - version: '', - }, - id: 'endpoint', - policy_id: '', - policy_ids: [], - enabled: true, - namespace: '', - revision: 0, - updated_at: '', - updated_by: '', - created_at: '', - created_by: '', - inputs: [ - { - type: 'endpoint', - enabled: true, - streams: [], - config: { - policy: { - value: { - windows: {}, - mac: {}, - linux: {}, - }, - }, - }, - }, - ], - }, - type: PACKAGE_POLICY_SAVED_OBJECT_TYPE, - references: [], - }; - }); - - /** Builds object key paths for all parent objects - * - * @param path e.g. `advanced.events.optionName` - * @returns e.g. ['advanced', 'advanced.events'] - */ - const getParentObjectKeyPaths = (path: string): string[] => - path - .split('.') // ['advanced', 'events', 'optionName'] - .slice(0, -1) // ['advanced', 'events'] - .map((parentObject) => path.match(`^.*${parentObject}`)![0]); // ['advanced', 'advanced.events'] - - describe(`when updating to model version ${TARGET_MODEL_VERSION}`, () => { - describe.each` - name | path | backfill - ${'aggregate_process'} | ${'advanced.events.aggregate_process'} | ${false} - ${'set_extended_host_information'} | ${'advanced.set_extended_host_information'} | ${true} - ${'alerts.hash.md5'} | ${'advanced.alerts.hash.md5'} | ${true} - ${'alerts.hash.sha1'} | ${'advanced.alerts.hash.sha1'} | ${true} - ${'events.hash.md5'} | ${'advanced.events.hash.md5'} | ${true} - ${'events.hash.sha1'} | ${'advanced.events.hash.sha1'} | ${true} - `( - 'backfilling `$name` with `$backfill`', - ({ path, backfill }: { path: string; backfill: boolean }) => { - it('should backfill when there are no advanced options yet', () => { - const migratedPolicyConfigSO = migrator.migrate({ - document: policyConfigSO, - fromVersion: TARGET_MODEL_VERSION - 1, - toVersion: TARGET_MODEL_VERSION, - }); - - const migratedPolicyConfig = getConfig(migratedPolicyConfigSO); - - expectConfigToHave(migratedPolicyConfig, path, backfill); - }); - - it.each(getParentObjectKeyPaths(path))( - 'should backfill without modifying other options in parent object `%s`', - (parentObjectKeyPath) => { - const policyConfig = getConfig(policyConfigSO); - const dummyField = `${parentObjectKeyPath}.cheese`; - set(policyConfig.windows, dummyField, 'brie'); - set(policyConfig.mac, dummyField, 'maasdam'); - set(policyConfig.linux, dummyField, 'camambert'); - - const migratedPolicyConfigSO = migrator.migrate({ - document: policyConfigSO, - fromVersion: TARGET_MODEL_VERSION - 1, - toVersion: TARGET_MODEL_VERSION, - }); - - const migratedPolicyConfig = getConfig(migratedPolicyConfigSO); - - expectConfigToHave(migratedPolicyConfig, path, backfill); - expect(migratedPolicyConfig.windows).toHaveProperty(dummyField, 'brie'); - expect(migratedPolicyConfig.mac).toHaveProperty(dummyField, 'maasdam'); - expect(migratedPolicyConfig.linux).toHaveProperty(dummyField, 'camambert'); - } - ); - - it('should not backfill if field is already present', () => { - const policyConfig = getConfig(policyConfigSO); - set(policyConfig.windows, path, !backfill); - set(policyConfig.mac, path, !backfill); - set(policyConfig.linux, path, !backfill); - - const migratedPolicyConfigSO = migrator.migrate({ - document: policyConfigSO, - fromVersion: TARGET_MODEL_VERSION - 1, - toVersion: TARGET_MODEL_VERSION, - }); - - const migratedPolicyConfig = getConfig(migratedPolicyConfigSO); - - expectConfigToHave(migratedPolicyConfig, path, !backfill); - }); - } - ); - }); - - const getConfig = (so: SavedObject) => - so.attributes.inputs[0].config?.policy.value; - - const expectConfigToHave = (config: any, path: string, value: string | boolean) => { - for (const os of ['windows', 'mac', 'linux']) { - expect(config[os]).toHaveProperty(path, value); - } - }; -}); diff --git a/x-pack/plugins/fleet/server/saved_objects/model_versions/security_solution/v15_advanced_package_policy_fields.ts b/x-pack/plugins/fleet/server/saved_objects/model_versions/security_solution/v15_advanced_package_policy_fields.ts deleted file mode 100644 index 1fa21f3c94c1a..0000000000000 --- a/x-pack/plugins/fleet/server/saved_objects/model_versions/security_solution/v15_advanced_package_policy_fields.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { - SavedObjectModelDataBackfillFn, - SavedObjectUnsanitizedDoc, -} from '@kbn/core-saved-objects-server'; - -import type { PackagePolicy } from '../../../../common'; - -export const packagePolicyV15AdvancedFieldsForEndpointV816: SavedObjectModelDataBackfillFn< - PackagePolicy, - PackagePolicy -> = (packagePolicyDoc) => { - if (packagePolicyDoc.attributes.package?.name !== 'endpoint') { - return { attributes: packagePolicyDoc.attributes }; - } - - const updatedPackagePolicyDoc: SavedObjectUnsanitizedDoc = packagePolicyDoc; - - const input = updatedPackagePolicyDoc.attributes.inputs[0]; - - if (input && input.config) { - const policy = input.config.policy.value; - - for (const os of ['windows', 'mac', 'linux']) { - const policyPerOs = policy[os]; - - policyPerOs.advanced = { - set_extended_host_information: true, - ...policyPerOs.advanced, - - events: { - aggregate_process: false, - ...policyPerOs.advanced?.events, - - hash: { - md5: true, - sha1: true, - ...policyPerOs.advanced?.events?.hash, - }, - }, - - alerts: { - ...policyPerOs.advanced?.alerts, - - hash: { - md5: true, - sha1: true, - ...policyPerOs.advanced?.alerts?.hash, - }, - }, - }; - } - } - - return { attributes: updatedPackagePolicyDoc.attributes }; -}; diff --git a/x-pack/plugins/graph/public/helpers/kql_encoder.ts b/x-pack/plugins/graph/public/helpers/kql_encoder.ts index 25ac6b9c4280d..e1eeb0f2dc35b 100644 --- a/x-pack/plugins/graph/public/helpers/kql_encoder.ts +++ b/x-pack/plugins/graph/public/helpers/kql_encoder.ts @@ -10,7 +10,7 @@ import rison from '@kbn/rison'; import { Workspace } from '../types'; function escapeQuotes(str: string) { - return str.replace(/"/g, '\\"'); + return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); } export function asKQL(workspace: Workspace, joinBy: 'and' | 'or') { diff --git a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/dimension_panel.test.tsx index a354b54fb37e9..aa6837a7e3393 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/dimension_panel.test.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/dimension_panel.test.tsx @@ -373,7 +373,7 @@ describe('FormBasedDimensionEditor', () => { // // press arrow up to go back to the beginning await userEvent.type(comboBoxInput, '{ArrowUp}{ArrowUp}'); expect(getVisibleFieldSelectOptions()).toEqual(allOptions.slice(8)); - }); + }, 10000); // this test can be long running due to a big tree we're rendering and userEvent.type function that is slow it('should hide fields that have no data', () => { (useExistingFieldsReader as jest.Mock).mockImplementationOnce(() => { diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_main_template/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_main_template/index.tsx index f4ef2044a38c7..3f05d872f6d1f 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_main_template/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_main_template/index.tsx @@ -7,12 +7,13 @@ import { EuiFlexGroup, EuiPageHeaderProps } from '@elastic/eui'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { entityCentricExperience } from '@kbn/observability-plugin/common'; import { ObservabilityPageTemplateProps } from '@kbn/observability-shared-plugin/public'; import type { KibanaPageTemplateProps } from '@kbn/shared-ux-page-kibana-template'; import React, { useContext } from 'react'; import { useLocation } from 'react-router-dom'; import { FeatureFeedbackButton } from '@kbn/observability-shared-plugin/public'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { isLogsSignal } from '../../../../utils/get_signal_type'; import { useLocalStorage } from '../../../../hooks/use_local_storage'; import { useDefaultAiAssistantStarterPromptsForAPM } from '../../../../hooks/use_default_ai_assistant_starter_prompts_for_apm'; import { KibanaEnvironmentContext } from '../../../../context/kibana_environment_context/kibana_environment_context'; @@ -71,12 +72,8 @@ export function ApmMainTemplate({ const { http, docLinks, observabilityShared, application } = services; const { kibanaVersion, isCloudEnv, isServerlessEnv } = kibanaEnvironment; const basePath = http?.basePath.get(); - const { config, core } = useApmPluginContext(); - const isEntityCentricExperienceSettingEnabled = core.uiSettings.get( - entityCentricExperience, - true - ); - + const { config } = useApmPluginContext(); + const { serviceEntitySummary } = useApmServiceContext(); const { isEntityCentricExperienceEnabled } = useEntityCentricExperienceSetting(); const ObservabilityPageTemplate = observabilityShared.navigation.PageTemplate; @@ -97,9 +94,14 @@ export function ApmMainTemplate({ [application?.capabilities.savedObjectsManagement.edit] ); - const shouldBypassNoDataScreen = bypassNoDataScreenPaths.some((path) => - location.pathname.includes(path) - ); + const hasLogsData = serviceEntitySummary?.dataStreamTypes + ? serviceEntitySummary?.dataStreamTypes?.length > 0 && + isLogsSignal(serviceEntitySummary.dataStreamTypes) + : false; + + const shouldBypassNoDataScreen = + bypassNoDataScreenPaths.some((path) => location.pathname.includes(path)) || + (isEntityCentricExperienceEnabled && hasLogsData); const { data: fleetApmPoliciesData, status: fleetApmPoliciesStatus } = useFetcher( (callApmApi) => { @@ -158,7 +160,7 @@ export function ApmMainTemplate({ const showEntitiesInventoryCallout = !dismissedEntitiesInventoryCallout && - isEntityCentricExperienceSettingEnabled && + isEntityCentricExperienceEnabled && selectedNavButton !== undefined; return ( diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/create_es_client/create_apm_event_client/index.ts b/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/create_es_client/create_apm_event_client/index.ts index c6c68830ae10c..cf376e7c78294 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/create_es_client/create_apm_event_client/index.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/create_es_client/create_apm_event_client/index.ts @@ -103,7 +103,7 @@ export class APMEventClient { /** @deprecated Use {@link excludedDataTiers} instead. * See https://www.elastic.co/guide/en/kibana/current/advanced-options.html **/ private readonly includeFrozen: boolean; - private readonly excludedDataTiers?: DataTier[]; + private readonly excludedDataTiers: DataTier[]; private readonly inspectableEsQueriesMap?: WeakMap; constructor(config: APMEventClientConfig) { @@ -112,7 +112,7 @@ export class APMEventClient { this.request = config.request; this.indices = config.indices; this.includeFrozen = config.options.includeFrozen; - this.excludedDataTiers = config.options.excludedDataTiers; + this.excludedDataTiers = config.options.excludedDataTiers ?? []; this.inspectableEsQueriesMap = config.options.inspectableEsQueriesMap; } @@ -167,7 +167,7 @@ export class APMEventClient { indices: this.indices, }); - if (this.excludedDataTiers) { + if (this.excludedDataTiers.length > 0) { filters.push(...excludeTiersQuery(this.excludedDataTiers)); } @@ -207,7 +207,8 @@ export class APMEventClient { // Reusing indices configured for errors since both events and errors are stored as logs. const index = processorEventsToIndex([ProcessorEvent.error], this.indices); - const filter = this.excludedDataTiers ? excludeTiersQuery(this.excludedDataTiers) : undefined; + const filter = + this.excludedDataTiers.length > 0 ? excludeTiersQuery(this.excludedDataTiers) : undefined; const searchParams = { ...omit(params, 'body'), @@ -249,7 +250,7 @@ export class APMEventClient { indices: this.indices, }); - if (this.excludedDataTiers) { + if (this.excludedDataTiers.length > 0) { filters.push(...excludeTiersQuery(this.excludedDataTiers)); } diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/tier_filter.ts b/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/tier_filter.ts index ae29575c044c6..cad0b03579e3d 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/tier_filter.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/tier_filter.ts @@ -13,10 +13,10 @@ export function getDataTierFilterCombined({ excludedDataTiers, }: { filter?: QueryDslQueryContainer; - excludedDataTiers?: DataTier[]; + excludedDataTiers: DataTier[]; }): QueryDslQueryContainer | undefined { if (!filter) { - return excludedDataTiers ? excludeTiersQuery(excludedDataTiers)[0] : undefined; + return excludedDataTiers.length > 0 ? excludeTiersQuery(excludedDataTiers)[0] : undefined; } return !excludedDataTiers diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts index 795700bfc9441..d3fad141335de 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts @@ -194,16 +194,20 @@ export const useDegradedDocsChart = () => { const extraActions: Action[] = [getOpenInLensAction, getOpenInLogsExplorerAction]; - return { - attributes, - dataView, - breakdown: { + const breakdown = useMemo(() => { + return { dataViewField: breakdownDataViewField, fieldSupportsBreakdown: breakdownDataViewField ? fieldSupportsBreakdown(breakdownDataViewField) : true, onChange: handleBreakdownFieldChange, - }, + }; + }, [breakdownDataViewField, handleBreakdownFieldChange]); + + return { + attributes, + dataView, + breakdown, extraActions, isChartLoading, onChartLoading: handleChartLoading, diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/template/page.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/template/page.tsx index 363fc88c8a490..c6e8790eeff6a 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/template/page.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/template/page.tsx @@ -8,6 +8,8 @@ import React, { useEffect } from 'react'; import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; import { EuiLoadingSpinner } from '@elastic/eui'; +import { useEntityCentricExperienceSetting } from '../../../hooks/use_entity_centric_experience_setting'; +import { isPending } from '../../../hooks/use_fetcher'; import { SYSTEM_INTEGRATION } from '../../../../common/constants'; import { useMetricsBreadcrumbs } from '../../../hooks/use_metrics_breadcrumbs'; import { useParentBreadcrumbResolver } from '../../../hooks/use_parent_breadcrumb_resolver'; @@ -24,7 +26,7 @@ import { InfraPageTemplate } from '../../shared/templates/infra_page_template'; import { OnboardingFlow } from '../../shared/templates/no_data_config'; import { PageTitleWithPopover } from '../header/page_title_with_popover'; import { useEntitySummary } from '../hooks/use_entity_summary'; -import { isMetricsSignal } from '../utils/get_data_stream_types'; +import { isLogsSignal, isMetricsSignal } from '../utils/get_data_stream_types'; const DATA_AVAILABILITY_PER_TYPE: Partial> = { host: [SYSTEM_INTEGRATION], @@ -36,10 +38,11 @@ export const Page = ({ tabs = [], links = [] }: ContentTemplateProps) => { const { rightSideItems, tabEntries, breadcrumbs: headerBreadcrumbs } = usePageHeader(tabs, links); const { asset } = useAssetDetailsRenderPropsContext(); const trackOnlyOnce = React.useRef(false); - const { dataStreams } = useEntitySummary({ + const { dataStreams, status: entitySummaryStatus } = useEntitySummary({ entityType: asset.type, entityId: asset.id, }); + const { isEntityCentricExperienceEnabled } = useEntityCentricExperienceSetting(); const { activeTabId } = useTabSwitcherContext(); const { services: { telemetry }, @@ -85,10 +88,18 @@ export const Page = ({ tabs = [], links = [] }: ContentTemplateProps) => { }, [activeTabId, asset.type, metadata, metadataLoading, telemetry]); const showPageTitleWithPopover = asset.type === 'host' && !isMetricsSignal(dataStreams); + const shouldBypassOnboarding = + isEntityCentricExperienceEnabled && (isLogsSignal(dataStreams) || isMetricsSignal(dataStreams)); return ( & { dataAvailabilityModules?: string[]; @@ -41,14 +41,18 @@ export const InfraPageTemplate = ({ const { error: dataViewLoadError, refetch: loadDataView } = useMetricsDataViewContext(); const { remoteClustersExist } = source?.status ?? {}; - const { data, status } = useFetcher(async (callApi) => { - return await callApi('/api/metrics/source/hasData', { - method: 'GET', - query: { - modules: dataAvailabilityModules, - }, - }); - }); + const { data, status } = useFetcher( + async (callApi) => { + if (!onboardingFlow) return; + return await callApi('/api/metrics/source/hasData', { + method: 'GET', + query: { + modules: dataAvailabilityModules, + }, + }); + }, + [onboardingFlow, dataAvailabilityModules] + ); const hasData = !!data?.hasData; const noDataConfig = getNoDataConfig({ diff --git a/x-pack/plugins/observability_solution/infra/public/components/shared/templates/no_data_config.ts b/x-pack/plugins/observability_solution/infra/public/components/shared/templates/no_data_config.ts index faf53cccca4cd..3859f93ddc437 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/shared/templates/no_data_config.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/shared/templates/no_data_config.ts @@ -108,11 +108,11 @@ export const getNoDataConfig = ({ }: { hasData: boolean; loading: boolean; - onboardingFlow: OnboardingFlow; + onboardingFlow?: OnboardingFlow; locators: LocatorClient; docsLink?: string; }): NoDataConfig | undefined => { - if (hasData || loading) { + if (!onboardingFlow || hasData || loading) { return; } diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_entity_centric_experience_setting.tsx b/x-pack/plugins/observability_solution/infra/public/hooks/use_entity_centric_experience_setting.tsx new file mode 100644 index 0000000000000..1cbc4680405e4 --- /dev/null +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_entity_centric_experience_setting.tsx @@ -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 { entityCentricExperience } from '@kbn/observability-plugin/common'; +import { useKibanaContextForPlugin } from './use_kibana'; + +export function useEntityCentricExperienceSetting() { + const { uiSettings } = useKibanaContextForPlugin().services; + + const isEntityCentricExperienceEnabled = uiSettings.get(entityCentricExperience, true); + + return { isEntityCentricExperienceEnabled }; +} diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/index.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/index.tsx index c013cebb42e70..b3d82e0c8fc22 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/index.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/index.tsx @@ -10,6 +10,7 @@ import React from 'react'; import { useTrackPageview } from '@kbn/observability-shared-plugin/public'; import { APP_WRAPPER_CLASS } from '@kbn/core/public'; import { css } from '@emotion/react'; +import { OnboardingFlow } from '../../../components/shared/templates/no_data_config'; import { InfraPageTemplate } from '../../../components/shared/templates/infra_page_template'; import { useMetricsBreadcrumbs } from '../../../hooks/use_metrics_breadcrumbs'; import { inventoryTitle } from '../../../translations'; @@ -38,6 +39,7 @@ export const SnapshotPage = () => {
, ], diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx index 3934abb5478f9..0de2ae8f6fbe7 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx @@ -11,6 +11,7 @@ import moment from 'moment'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { InventoryMetric, InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; import { decodeOrThrow } from '@kbn/io-ts-utils'; +import { OnboardingFlow } from '../../../../components/shared/templates/no_data_config'; import { InfraPageTemplate } from '../../../../components/shared/templates/infra_page_template'; import { NodeDetailsMetricDataResponseRT } from '../../../../../common/http_api/node_details_api'; import { isPending, useFetcher } from '../../../../hooks/use_fetcher'; @@ -91,6 +92,7 @@ export const NodeDetailsPage = (props: Props) => { return ( { if (metadataLoading && !filteredRequiredMetrics.length) { return ( - + { return ( { const dispatch = useDispatch(); @@ -118,7 +120,7 @@ export const InvestigateInTimelineButton: FC< diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/alert_count_insight.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/alert_count_insight.test.tsx index f0d16a418f2b2..5e4650179291d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/alert_count_insight.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/alert_count_insight.test.tsx @@ -48,6 +48,7 @@ describe('AlertCountInsight', () => { const { getByTestId } = renderAlertCountInsight(); expect(getByTestId(testId)).toBeInTheDocument(); expect(getByTestId(`${testId}-distribution-bar`)).toBeInTheDocument(); + expect(getByTestId(`${testId}-count`)).toHaveTextContent('177'); }); it('renders loading spinner if data is being fetched', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/alert_count_insight.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/alert_count_insight.tsx index 566b77b5739a9..08325584bd8cb 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/alert_count_insight.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/alert_count_insight.tsx @@ -16,8 +16,12 @@ import { getIsAlertsBySeverityData, getSeverityColor, } from '../../../../detections/components/alerts_kpis/severity_level_panel/helpers'; +import { FormattedCount } from '../../../../common/components/formatted_number'; +import { InvestigateInTimelineButton } from '../../../../common/components/event_details/investigate_in_timeline_button'; +import { getDataProvider } from '../../../../common/components/event_details/use_action_cell_data_provider'; const ENTITY_ALERT_COUNT_ID = 'entity-alert-count'; +const SEVERITIES = ['unknown', 'low', 'medium', 'high', 'critical']; interface AlertCountInsightProps { /** @@ -39,7 +43,7 @@ interface AlertCountInsightProps { } /* - * Displays a distribution bar with the count of critical alerts for a given entity + * Displays a distribution bar with the total alert count for a given entity */ export const AlertCountInsight: React.FC = ({ name, @@ -56,22 +60,27 @@ export const AlertCountInsight: React.FC = ({ uniqueQueryId, signalIndexName: null, }); + const dataProviders = useMemo( + () => [getDataProvider(fieldName, `timeline-indicator-${fieldName}-${name}`, name)], + [fieldName, name] + ); const data = useMemo(() => (getIsAlertsBySeverityData(items) ? items : []), [items]); - const alertStats = useMemo(() => { - return data.map((item) => ({ - key: item.key, - count: item.value, - color: getSeverityColor(item.key), - })); - }, [data]); - - const count = useMemo( - () => data.filter((item) => item.key === 'critical')[0]?.value ?? 0, + const alertStats = useMemo( + () => + data + .map((item) => ({ + key: item.key, + count: item.value, + color: getSeverityColor(item.key), + })) + .sort((a, b) => SEVERITIES.indexOf(a.key) - SEVERITIES.indexOf(b.key)), [data] ); + const totalAlertCount = useMemo(() => data.reduce((acc, item) => acc + item.value, 0), [data]); + if (!isLoading && items.length === 0) return null; return ( @@ -87,7 +96,17 @@ export const AlertCountInsight: React.FC = ({ /> } stats={alertStats} - count={count} + count={ +
+ + + +
+ } direction={direction} data-test-subj={`${dataTestSubj}-distribution-bar`} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/insight_distribution_bar.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/insight_distribution_bar.test.tsx index a775da8a7f73a..405c0528a9b2c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/insight_distribution_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/insight_distribution_bar.test.tsx @@ -11,7 +11,7 @@ import { InsightDistributionBar } from './insight_distribution_bar'; import { TestProviders } from '../../../../common/mock'; const title = 'test title'; -const count = 10; +const count =
{'100'}
; const testId = 'test-id'; const stats = [ { @@ -35,7 +35,7 @@ describe('', () => { ); expect(getByTestId(testId)).toBeInTheDocument(); expect(getByText(title)).toBeInTheDocument(); - expect(getByTestId(`${testId}-badge`)).toHaveTextContent(`${count}`); + expect(getByTestId('test-count')).toBeInTheDocument(); expect(getByTestId(`${testId}-distribution-bar`)).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/insight_distribution_bar.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/insight_distribution_bar.tsx index 006ec8c5dad4f..083738e6766bc 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/insight_distribution_bar.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/insight_distribution_bar.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { css } from '@emotion/css'; import { EuiFlexGroup, @@ -17,7 +17,6 @@ import { type EuiFlexGroupProps, } from '@elastic/eui'; import { DistributionBar } from '@kbn/security-solution-distribution-bar'; -import { FormattedCount } from '../../../../common/components/formatted_number'; export interface InsightDistributionBarProps { /** @@ -31,7 +30,7 @@ export interface InsightDistributionBarProps { /** * Count to be displayed in the badge */ - count: number; + count: React.ReactNode; /** * Flex direction of the component */ @@ -53,34 +52,53 @@ export const InsightDistributionBar: React.FC = ({ const { euiTheme } = useEuiTheme(); const xsFontSize = useEuiFontSize('xs').fontSize; + const barComponent = useMemo( + () => ( + + + + + + {count} + + + ), + [stats, count, dataTestSubj] + ); + return ( - - + + {title} - - - - - - - - - - - - + {direction === 'column' ? ( + + {barComponent} + + ) : ( + {barComponent} + )} ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.test.tsx index 296a61f444a17..8976a01eedbc4 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.test.tsx @@ -10,34 +10,87 @@ import { render } from '@testing-library/react'; import { TestProviders } from '../../../../common/mock'; import { MisconfigurationsInsight } from './misconfiguration_insight'; import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'; +import { DocumentDetailsContext } from '../context'; +import { mockFlyoutApi } from '../mocks/mock_flyout_context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { mockContextValue } from '../mocks/mock_context'; +import { HostPreviewPanelKey } from '../../../entity_details/host_right'; +import { HOST_PREVIEW_BANNER } from '../../right/components/host_entity_overview'; +import { UserPreviewPanelKey } from '../../../entity_details/user_right'; +import { USER_PREVIEW_BANNER } from '../../right/components/user_entity_overview'; +jest.mock('@kbn/expandable-flyout'); jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'); -const fieldName = 'host.name'; -const name = 'test host'; +const hostName = 'test host'; +const userName = 'test user'; const testId = 'test'; -const renderMisconfigurationsInsight = () => { +const renderMisconfigurationsInsight = (fieldName: 'host.name' | 'user.name', value: string) => { return render( - + + + ); }; describe('MisconfigurationsInsight', () => { + beforeEach(() => { + jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi); + }); + it('renders', () => { (useMisconfigurationPreview as jest.Mock).mockReturnValue({ data: { count: { passed: 1, failed: 2 } }, }); - const { getByTestId } = renderMisconfigurationsInsight(); + const { getByTestId } = renderMisconfigurationsInsight('host.name', hostName); expect(getByTestId(testId)).toBeInTheDocument(); expect(getByTestId(`${testId}-distribution-bar`)).toBeInTheDocument(); }); it('renders null if no misconfiguration data found', () => { (useMisconfigurationPreview as jest.Mock).mockReturnValue({}); - const { container } = renderMisconfigurationsInsight(); + const { container } = renderMisconfigurationsInsight('host.name', hostName); expect(container).toBeEmptyDOMElement(); }); + + describe('should open entity flyout when clicking on badge', () => { + it('should open host entity flyout when clicking on host badge', () => { + (useMisconfigurationPreview as jest.Mock).mockReturnValue({ + data: { count: { passed: 1, failed: 2 } }, + }); + const { getByTestId } = renderMisconfigurationsInsight('host.name', hostName); + expect(getByTestId(`${testId}-count`)).toHaveTextContent('3'); + + getByTestId(`${testId}-count`).click(); + expect(mockFlyoutApi.openPreviewPanel).toHaveBeenCalledWith({ + id: HostPreviewPanelKey, + params: { + hostName, + banner: HOST_PREVIEW_BANNER, + scopeId: mockContextValue.scopeId, + }, + }); + }); + + it('should open user entity flyout when clicking on user badge', () => { + (useMisconfigurationPreview as jest.Mock).mockReturnValue({ + data: { count: { passed: 2, failed: 3 } }, + }); + const { getByTestId } = renderMisconfigurationsInsight('user.name', userName); + expect(getByTestId(`${testId}-count`)).toHaveTextContent('5'); + + getByTestId(`${testId}-count`).click(); + expect(mockFlyoutApi.openPreviewPanel).toHaveBeenCalledWith({ + id: UserPreviewPanelKey, + params: { + userName, + banner: USER_PREVIEW_BANNER, + scopeId: mockContextValue.scopeId, + }, + }); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.tsx index 552a242c84893..961fa1d5f3a45 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.tsx @@ -6,12 +6,16 @@ */ import React, { useMemo } from 'react'; -import { EuiFlexItem, type EuiFlexGroupProps } from '@elastic/eui'; +import { EuiFlexItem, type EuiFlexGroupProps, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/css'; import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'; import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { InsightDistributionBar } from './insight_distribution_bar'; import { getFindingsStats } from '../../../../cloud_security_posture/components/misconfiguration/misconfiguration_preview'; +import { FormattedCount } from '../../../../common/components/formatted_number'; +import { PreviewLink } from '../../../shared/components/preview_link'; +import { useDocumentDetailsContext } from '../context'; interface MisconfigurationsInsightProps { /** @@ -33,7 +37,7 @@ interface MisconfigurationsInsightProps { } /* - * Displays a distribution bar with the count of failed misconfigurations for a given entity + * Displays a distribution bar with the count of total misconfigurations for a given entity */ export const MisconfigurationsInsight: React.FC = ({ name, @@ -41,6 +45,8 @@ export const MisconfigurationsInsight: React.FC = direction, 'data-test-subj': dataTestSubj, }) => { + const { scopeId, isPreview } = useDocumentDetailsContext(); + const { euiTheme } = useEuiTheme(); const { data } = useMisconfigurationPreview({ query: buildEntityFlyoutPreviewQuery(fieldName, name), sort: [], @@ -50,13 +56,39 @@ export const MisconfigurationsInsight: React.FC = const passedFindings = data?.count.passed || 0; const failedFindings = data?.count.failed || 0; - const hasMisconfigurationFindings = passedFindings > 0 || failedFindings > 0; + const totalFindings = useMemo( + () => passedFindings + failedFindings, + [passedFindings, failedFindings] + ); + const hasMisconfigurationFindings = totalFindings > 0; const misconfigurationsStats = useMemo( () => getFindingsStats(passedFindings, failedFindings), [passedFindings, failedFindings] ); + const count = useMemo( + () => ( +
+ + + +
+ ), + [totalFindings, fieldName, name, scopeId, isPreview, dataTestSubj, euiTheme.size] + ); + if (!hasMisconfigurationFindings) return null; return ( @@ -69,7 +101,7 @@ export const MisconfigurationsInsight: React.FC = /> } stats={misconfigurationsStats} - count={failedFindings} + count={count} direction={direction} data-test-subj={`${dataTestSubj}-distribution-bar`} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.test.tsx index 77c6737266b89..cfac8703fbc89 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.test.tsx @@ -10,7 +10,14 @@ import { render } from '@testing-library/react'; import React from 'react'; import { VulnerabilitiesInsight } from './vulnerabilities_insight'; import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; +import { DocumentDetailsContext } from '../context'; +import { mockFlyoutApi } from '../mocks/mock_flyout_context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { mockContextValue } from '../mocks/mock_context'; +import { HostPreviewPanelKey } from '../../../entity_details/host_right'; +import { HOST_PREVIEW_BANNER } from '../../right/components/host_entity_overview'; +jest.mock('@kbn/expandable-flyout'); jest.mock('@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'); const hostName = 'test host'; @@ -19,15 +26,21 @@ const testId = 'test'; const renderVulnerabilitiesInsight = () => { return render( - + + + ); }; describe('VulnerabilitiesInsight', () => { + beforeEach(() => { + jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi); + }); + it('renders', () => { (useVulnerabilitiesPreview as jest.Mock).mockReturnValue({ - data: { count: { CRITICAL: 0, HIGH: 1, MEDIUM: 1, LOW: 0, UNKNOWN: 0 } }, + data: { count: { CRITICAL: 0, HIGH: 1, MEDIUM: 1, LOW: 0, NONE: 0 } }, }); const { getByTestId } = renderVulnerabilitiesInsight(); @@ -35,6 +48,24 @@ describe('VulnerabilitiesInsight', () => { expect(getByTestId(`${testId}-distribution-bar`)).toBeInTheDocument(); }); + it('opens host preview when click on count badge', () => { + (useVulnerabilitiesPreview as jest.Mock).mockReturnValue({ + data: { count: { CRITICAL: 1, HIGH: 2, MEDIUM: 1, LOW: 2, NONE: 2 } }, + }); + const { getByTestId } = renderVulnerabilitiesInsight(); + expect(getByTestId(`${testId}-count`)).toHaveTextContent('8'); + + getByTestId(`${testId}-count`).click(); + expect(mockFlyoutApi.openPreviewPanel).toHaveBeenCalledWith({ + id: HostPreviewPanelKey, + params: { + hostName, + banner: HOST_PREVIEW_BANNER, + scopeId: mockContextValue.scopeId, + }, + }); + }); + it('renders null when data is not available', () => { (useVulnerabilitiesPreview as jest.Mock).mockReturnValue({}); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.tsx index 4c581b6db57d0..c675c0a0e079b 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.tsx @@ -6,12 +6,16 @@ */ import React, { useMemo } from 'react'; -import { EuiFlexItem, type EuiFlexGroupProps } from '@elastic/eui'; +import { EuiFlexItem, type EuiFlexGroupProps, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/css'; import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { getVulnerabilityStats, hasVulnerabilitiesData } from '@kbn/cloud-security-posture'; import { InsightDistributionBar } from './insight_distribution_bar'; +import { FormattedCount } from '../../../../common/components/formatted_number'; +import { PreviewLink } from '../../../shared/components/preview_link'; +import { useDocumentDetailsContext } from '../context'; interface VulnerabilitiesInsightProps { /** @@ -29,13 +33,15 @@ interface VulnerabilitiesInsightProps { } /* - * Displays a distribution bar with the count of critical vulnerabilities for a given host + * Displays a distribution bar and the total vulnerabilities count for a given host */ export const VulnerabilitiesInsight: React.FC = ({ hostName, direction, 'data-test-subj': dataTestSubj, }) => { + const { scopeId, isPreview } = useDocumentDetailsContext(); + const { euiTheme } = useEuiTheme(); const { data } = useVulnerabilitiesPreview({ query: buildEntityFlyoutPreviewQuery('host.name', hostName), sort: [], @@ -44,6 +50,11 @@ export const VulnerabilitiesInsight: React.FC = ({ }); const { CRITICAL = 0, HIGH = 0, MEDIUM = 0, LOW = 0, NONE = 0 } = data?.count || {}; + const totalVulnerabilities = useMemo( + () => CRITICAL + HIGH + MEDIUM + LOW + NONE, + [CRITICAL, HIGH, MEDIUM, LOW, NONE] + ); + const hasVulnerabilitiesFindings = useMemo( () => hasVulnerabilitiesData({ @@ -68,6 +79,28 @@ export const VulnerabilitiesInsight: React.FC = ({ [CRITICAL, HIGH, MEDIUM, LOW, NONE] ); + const count = useMemo( + () => ( +
+ + + +
+ ), + [totalVulnerabilities, hostName, scopeId, isPreview, dataTestSubj, euiTheme.size] + ); + if (!hasVulnerabilitiesFindings) return null; return ( @@ -80,7 +113,7 @@ export const VulnerabilitiesInsight: React.FC = ({ /> } stats={vulnerabilitiesStats} - count={CRITICAL} + count={count} direction={direction} data-test-subj={`${dataTestSubj}-distribution-bar`} /> diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts b/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts index d948cb5711f38..964936b310a41 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts @@ -2014,7 +2014,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.events.aggregate_process', { defaultMessage: - 'Reduce event volume by merging related process events into fewer aggregate events. Default is true.', + 'Reduce event volume by merging related process events into fewer aggregate events. Default is false.', } ), }, @@ -2025,7 +2025,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.linux.advanced.events.aggregate_process', { defaultMessage: - 'Reduce event volume by merging related process events into fewer aggregate events. Default is true.', + 'Reduce event volume by merging related process events into fewer aggregate events. Default is false.', } ), }, @@ -2036,7 +2036,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.mac.advanced.events.aggregate_process', { defaultMessage: - 'Reduce event volume by merging related process events into fewer aggregate events. Default is true.', + 'Reduce event volume by merging related process events into fewer aggregate events. Default is false.', } ), }, @@ -2047,7 +2047,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.alerts.hash.md5', { defaultMessage: - 'Compute and include MD5 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: false', + 'Compute and include MD5 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: true', } ), }, @@ -2058,7 +2058,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.alerts.hash.sha1', { defaultMessage: - 'Compute and include SHA-1 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: false', + 'Compute and include SHA-1 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: true', } ), }, @@ -2069,7 +2069,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.events.hash.md5', { defaultMessage: - 'Compute and include MD5 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: false', + 'Compute and include MD5 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: true', } ), }, @@ -2080,7 +2080,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.events.hash.sha1', { defaultMessage: - 'Compute and include SHA-1 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: false', + 'Compute and include SHA-1 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: true', } ), }, @@ -2102,7 +2102,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.linux.advanced.alerts.hash.md5', { defaultMessage: - 'Compute and include MD5 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: false', + 'Compute and include MD5 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: true', } ), }, @@ -2113,7 +2113,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.linux.advanced.alerts.hash.sha1', { defaultMessage: - 'Compute and include SHA-1 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: false', + 'Compute and include SHA-1 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: true', } ), }, @@ -2124,7 +2124,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.linux.advanced.events.hash.md5', { defaultMessage: - 'Compute and include MD5 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: false', + 'Compute and include MD5 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: true', } ), }, @@ -2135,7 +2135,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.linux.advanced.events.hash.sha1', { defaultMessage: - 'Compute and include SHA-1 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: false', + 'Compute and include SHA-1 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: true', } ), }, @@ -2157,7 +2157,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.mac.advanced.alerts.hash.md5', { defaultMessage: - 'Compute and include MD5 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: false', + 'Compute and include MD5 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: true', } ), }, @@ -2168,7 +2168,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.mac.advanced.alerts.hash.sha1', { defaultMessage: - 'Compute and include SHA-1 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: false', + 'Compute and include SHA-1 hashes in alerts? This will increase CPU usage and alert sizes. If any user exceptionlist, trustlist, or blocklists reference this hash type, Endpoint will ignore this setting and automatically enable this hash type. Default: true', } ), }, @@ -2179,7 +2179,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.mac.advanced.events.hash.md5', { defaultMessage: - 'Compute and include MD5 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: false', + 'Compute and include MD5 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: true', } ), }, @@ -2190,7 +2190,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.mac.advanced.events.hash.sha1', { defaultMessage: - 'Compute and include SHA-1 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: false', + 'Compute and include SHA-1 hashes for processes and libraries in events? This will increase CPU usage and event sizes. Default: true', } ), }, @@ -2212,7 +2212,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.set_extended_host_information', { defaultMessage: - 'Include more details about hosts in events? Set to false to receive only id, name and os. Setting to true will increase event size. Default: false', + 'Include more details about hosts in events? Set to false to receive only id, name and os. Setting to true will increase event size. Default: true', } ), }, @@ -2223,7 +2223,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.mac.advanced.set_extended_host_information', { defaultMessage: - 'Include more details about hosts in events? Set to false to receive only id, name and os. Setting to true will increase event size. Default: false', + 'Include more details about hosts in events? Set to false to receive only id, name and os. Setting to true will increase event size. Default: true', } ), }, @@ -2234,7 +2234,7 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ 'xpack.securitySolution.endpoint.policy.advanced.linux.advanced.set_extended_host_information', { defaultMessage: - 'Include more details about hosts in events? Set to false to receive only id, name and os. Setting to true will increase event size. Default: false', + 'Include more details about hosts in events? Set to false to receive only id, name and os. Setting to true will increase event size. Default: true', } ), }, diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/event_merging_banner.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/event_merging_banner.tsx index 26b229e219c2e..ec76a416e390d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/event_merging_banner.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/event_merging_banner.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { EuiCallOut, EuiLink, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { ENDPOINT_VERSION_SUPPORTING_EVENT_MERGING_BY_DEFAULT } from '../constants'; export interface EventMergingBannerProps { onDismiss: () => void; @@ -29,7 +30,7 @@ export const EventMergingBanner = memo(({ onDismiss }) (({ onDismiss }) /> ), + minVersion: ENDPOINT_VERSION_SUPPORTING_EVENT_MERGING_BY_DEFAULT, }} /> diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/constants.ts b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/constants.ts new file mode 100644 index 0000000000000..19f1e36163aad --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/constants.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Event merging banner is hidden temporarily for 8.16 (and serverless). + * Probably will be enabled for 8.17 or 8.18, when we can change the defaults and trigger policy deploy by migration. + * Blocker issue: https://github.com/elastic/kibana/issues/193352 + */ +export const ALLOW_SHOWING_EVENT_MERGING_BANNER = false; + +/** + * The version from which we decrease event volume by default. + */ +export const ENDPOINT_VERSION_SUPPORTING_EVENT_MERGING_BY_DEFAULT = '8.17'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/policy_settings_form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/policy_settings_form.test.tsx index d2e4c58adfb56..19a5ec8e6df39 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/policy_settings_form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/policy_settings_form.test.tsx @@ -27,6 +27,13 @@ import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; jest.mock('../../../../../common/hooks/use_license'); +const mockAllowShowingEventMergingBannerConstantGetter = jest.fn(); +jest.mock('./constants', () => ({ + get ALLOW_SHOWING_EVENT_MERGING_BANNER() { + return mockAllowShowingEventMergingBannerConstantGetter(); + }, +})); + describe('Endpoint Policy Settings Form', () => { const testSubj = getPolicySettingsFormTestSubjects('test'); @@ -50,10 +57,23 @@ describe('Endpoint Policy Settings Form', () => { 'data-test-subj': 'test', }; + mockAllowShowingEventMergingBannerConstantGetter.mockReturnValue(false); + render = () => (renderResult = mockedContext.render()); }); describe('event merging banner', () => { + beforeEach(() => { + mockAllowShowingEventMergingBannerConstantGetter.mockReturnValue(true); + }); + + it('should hide the banner if its not allowed to be displayed', () => { + mockAllowShowingEventMergingBannerConstantGetter.mockReturnValue(false); + + render(); + + expect(renderResult.queryByTestId('eventMergingCallout')).not.toBeInTheDocument(); + }); it('should show the event merging banner for 8.16 if it has never been dismissed', () => { render(); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/policy_settings_form.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/policy_settings_form.tsx index 7d83170df2d26..619ba07346f47 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/policy_settings_form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/policy_settings_form.tsx @@ -26,6 +26,7 @@ import { MalwareProtectionsCard } from './components/cards/malware_protections_c import type { PolicyFormComponentCommonProps } from './types'; import { AdvancedSection } from './components/advanced_section'; import { useTestIdGenerator } from '../../../../hooks/use_test_id_generator'; +import { ALLOW_SHOWING_EVENT_MERGING_BANNER } from './constants'; const PROTECTIONS_SECTION_TITLE = i18n.translate( 'xpack.securitySolution.endpoint.policy.details.protections', @@ -45,7 +46,8 @@ export const PolicySettingsForm = memo((props) => { const { storage } = useKibana().services; const [showEventMergingBanner, setShowEventMergingBanner] = useState( - storage.get('securitySolution.showEventMergingBanner') ?? true + ALLOW_SHOWING_EVENT_MERGING_BANNER && + (storage.get('securitySolution.showEventMergingBanner') ?? true) ); const onBannerDismiss = useCallback(() => { setShowEventMergingBanner(false); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx index e2aa8c42511d7..eae2eec549dfe 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx @@ -10,7 +10,6 @@ import { EuiButtonEmpty, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiToolTip } import styled from 'styled-components'; import { useDispatch } from 'react-redux'; import { dataTableSelectors, tableDefaults } from '@kbn/securitysolution-data-table'; -import type { TableId } from '@kbn/securitysolution-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { DocumentDetailsRightPanelKey } from '../../../../../flyout/document_details/shared/constants/panel_keys'; import { useSourcererDataView } from '../../../../../sourcerer/containers'; @@ -32,7 +31,6 @@ import { useTimelineFullScreen, useGlobalFullScreen, } from '../../../../../common/containers/use_full_screen'; -import { detectionsTimelineIds } from '../../../../containers/helpers'; import { useUserPrivileges } from '../../../../../common/components/user_privileges'; import { timelineActions, timelineSelectors } from '../../../../store'; import { timelineDefaults } from '../../../../store/defaults'; @@ -273,18 +271,8 @@ export const useSessionView = ({ scopeId, height }: { scopeId: string; height?: [globalFullScreen, scopeId, timelineFullScreen] ); - const sourcererScope = useMemo(() => { - if (isActiveTimeline(scopeId)) { - return SourcererScopeName.timeline; - } else if (detectionsTimelineIds.includes(scopeId as TableId)) { - return SourcererScopeName.detections; - } else { - return SourcererScopeName.default; - } - }, [scopeId]); - - const { selectedPatterns } = useSourcererDataView(sourcererScope); - const eventDetailsIndex = useMemo(() => selectedPatterns.join(','), [selectedPatterns]); + const { selectedPatterns } = useSourcererDataView(SourcererScopeName.detections); + const alertsIndex = useMemo(() => selectedPatterns.join(','), [selectedPatterns]); const { openFlyout } = useExpandableFlyoutApi(); const openAlertDetailsFlyout = useCallback( @@ -294,7 +282,7 @@ export const useSessionView = ({ scopeId, height }: { scopeId: string; height?: id: DocumentDetailsRightPanelKey, params: { id: eventId, - indexName: eventDetailsIndex, + indexName: alertsIndex, scopeId, }, }, @@ -304,7 +292,7 @@ export const useSessionView = ({ scopeId, height }: { scopeId: string; height?: panel: 'right', }); }, - [openFlyout, eventDetailsIndex, scopeId, telemetry] + [openFlyout, alertsIndex, scopeId, telemetry] ); const sessionViewComponent = useMemo(() => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index 173d722d782a1..0adc9c1d77d3d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -30,6 +30,7 @@ import { buildReasonMessageForEsqlAlert } from '../utils/reason_formatters'; import type { RulePreviewLoggedRequest } from '../../../../../common/api/detection_engine/rule_preview/rule_preview.gen'; import type { CreateRuleOptions, RunOpts, SignalSource } from '../types'; import { logEsqlRequest } from '../utils/logged_requests'; +import { getDataTierFilter } from '../utils/get_data_tier_filter'; import * as i18n from '../translations'; import { @@ -90,6 +91,10 @@ export const esqlExecutor = async ({ return withSecuritySpan('esqlExecutor', async () => { const result = createSearchAfterReturnType(); let size = tuple.maxSignals; + const dataTiersFilters = await getDataTierFilter({ + uiSettingsClient: services.uiSettingsClient, + }); + try { while ( result.createdSignalsCount <= tuple.maxSignals && @@ -100,7 +105,7 @@ export const esqlExecutor = async ({ from: tuple.from.toISOString(), to: tuple.to.toISOString(), size, - filters: [], + filters: dataTiersFilters, primaryTimestamp, secondaryTimestamp, exceptionFilter, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index bcee389d1d91b..92300d5580cbb 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -37,6 +37,8 @@ import { useStorage } from '@kbn/ml-local-storage'; import { useUrlState } from '@kbn/ml-url-state'; import { useFieldStatsFlyoutContext } from '@kbn/ml-field-stats-flyout'; +import { MAX_ROW_COUNT } from '@kbn/ml-data-grid/lib/common'; +import { FormattedMessage } from '@kbn/i18n-react'; import type { PivotAggDict } from '../../../../../../common/types/pivot_aggs'; import type { PivotGroupByDict } from '../../../../../../common/types/pivot_group_by'; import { TRANSFORM_FUNCTION } from '../../../../../../common/constants'; @@ -288,6 +290,14 @@ export const StepDefineForm: FC = React.memo((props) => { }; }); + const rowCountInfoLabel = ( + + ); + return (
@@ -467,6 +477,11 @@ export const StepDefineForm: FC = React.memo((props) => { label={i18n.translate('xpack.transform.stepDefineForm.dataGridLabel', { defaultMessage: 'Source documents', })} + labelAppend={ + indexPreviewProps.rowCount === MAX_ROW_COUNT && ( + {rowCountInfoLabel} + ) + } > @@ -503,6 +518,11 @@ export const StepDefineForm: FC = React.memo((props) => { label={i18n.translate('xpack.transform.stepDefineForm.previewLabel', { defaultMessage: 'Preview', })} + labelAppend={ + previewProps.rowCount === MAX_ROW_COUNT && ( + {rowCountInfoLabel} + ) + } > <> diff --git a/x-pack/test/api_integration/apis/management/index.js b/x-pack/test/api_integration/apis/management/index.js index d8a9ed76dd2f9..852348d8d243f 100644 --- a/x-pack/test/api_integration/apis/management/index.js +++ b/x-pack/test/api_integration/apis/management/index.js @@ -14,5 +14,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./index_management')); loadTestFile(require.resolve('./index_lifecycle_management')); loadTestFile(require.resolve('./snapshot_restore')); + loadTestFile(require.resolve('./ingest_pipelines')); }); } diff --git a/x-pack/test/api_integration/apis/management/ingest_pipelines/databases.ts b/x-pack/test/api_integration/apis/management/ingest_pipelines/databases.ts index 93a7ccc7d4088..98916ab04509e 100644 --- a/x-pack/test/api_integration/apis/management/ingest_pipelines/databases.ts +++ b/x-pack/test/api_integration/apis/management/ingest_pipelines/databases.ts @@ -13,17 +13,25 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const ingestPipelines = getService('ingestPipelines'); const url = `/api/ingest_pipelines/databases`; - const databaseName = 'GeoIP2-Anonymous-IP'; - const normalizedDatabaseName = 'geoip2-anonymous-ip'; + const maxmindDatabaseName = 'GeoIP2-Anonymous-IP'; + const normalizedMaxmindDatabaseName = 'geoip2-anonymous-ip'; + const ipinfoDatabaseName = 'asn'; + const normalizedIpinfoDatabaseName = 'asn'; - describe('Manage databases', function () { + // Failing: See https://github.com/elastic/kibana/issues/196765 + // Failing: See https://github.com/elastic/kibana/issues/196765 + describe.skip('Manage databases', function () { after(async () => { await ingestPipelines.api.deleteGeoipDatabases(); }); describe('Create', () => { - it('creates a geoip database when using a correct database name', async () => { - const database = { maxmind: '123456', databaseName }; + it('creates a maxmind geoip database when using a correct database name', async () => { + const database = { + databaseType: 'maxmind', + databaseName: maxmindDatabaseName, + maxmind: '123456', + }; const { body } = await supertest .post(url) .set('kbn-xsrf', 'xxx') @@ -31,13 +39,27 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); expect(body).to.eql({ - name: databaseName, - id: normalizedDatabaseName, + name: maxmindDatabaseName, + id: normalizedMaxmindDatabaseName, }); }); - it('creates a geoip database when using an incorrect database name', async () => { - const database = { maxmind: '123456', databaseName: 'Test' }; + it('creates an ipinfo geoip database when using a correct database name', async () => { + const database = { databaseType: 'ipinfo', databaseName: ipinfoDatabaseName }; + const { body } = await supertest + .post(url) + .set('kbn-xsrf', 'xxx') + .send(database) + .expect(200); + + expect(body).to.eql({ + name: ipinfoDatabaseName, + id: normalizedIpinfoDatabaseName, + }); + }); + + it('returns error when creating a geoip database with an incorrect database name', async () => { + const database = { databaseType: 'maxmind', databaseName: 'Test', maxmind: '123456' }; await supertest.post(url).set('kbn-xsrf', 'xxx').send(database).expect(400); }); }); @@ -47,8 +69,13 @@ export default function ({ getService }: FtrProviderContext) { const { body } = await supertest.get(url).set('kbn-xsrf', 'xxx').expect(200); expect(body).to.eql([ { - id: normalizedDatabaseName, - name: databaseName, + id: normalizedIpinfoDatabaseName, + name: ipinfoDatabaseName, + type: 'ipinfo', + }, + { + id: normalizedMaxmindDatabaseName, + name: maxmindDatabaseName, type: 'maxmind', }, ]); @@ -58,7 +85,12 @@ export default function ({ getService }: FtrProviderContext) { describe('Delete', () => { it('deletes a geoip database', async () => { await supertest - .delete(`${url}/${normalizedDatabaseName}`) + .delete(`${url}/${normalizedMaxmindDatabaseName}`) + .set('kbn-xsrf', 'xxx') + .expect(200); + + await supertest + .delete(`${url}/${normalizedIpinfoDatabaseName}`) .set('kbn-xsrf', 'xxx') .expect(200); }); diff --git a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts index bbdf53b3eda5c..dc9c74dfa07a5 100644 --- a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts +++ b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts @@ -326,7 +326,7 @@ export default function ({ getService }: FtrProviderContext) { await transform.wizard.assertAdvancedQueryEditorSwitchCheckState(false); await transform.testExecution.logTestStep('enables the index preview histogram charts'); - await transform.wizard.enableIndexPreviewHistogramCharts(false); + await transform.wizard.enableIndexPreviewHistogramCharts(true); await transform.testExecution.logTestStep('displays the index preview histogram charts'); await transform.wizard.assertIndexPreviewHistogramCharts( testData.expected.histogramCharts diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/esql.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/esql.ts index 723a2a7d2dfa3..bf431e0021053 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/esql.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/esql.ts @@ -14,6 +14,7 @@ import { getCreateEsqlRulesSchemaMock } from '@kbn/security-solution-plugin/comm import { RuleExecutionStatusEnum } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_monitoring'; import { getMaxSignalsWarning as getMaxAlertsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; +import { EXCLUDED_DATA_TIERS_FOR_RULE_EXECUTION } from '@kbn/security-solution-plugin/common/constants'; import { getPreviewAlerts, previewRule, @@ -25,6 +26,7 @@ import { scheduleRuleRun, stopAllManualRuns, waitForBackfillExecuted, + setAdvancedSettings, } from '../../../../utils'; import { deleteAllRules, @@ -1428,6 +1430,12 @@ export default ({ getService }: FtrProviderContext) => { await indexEnhancedDocuments({ documents: [doc1], interval, id }); }); + afterEach(async () => { + await setAdvancedSettings(supertest, { + [EXCLUDED_DATA_TIERS_FOR_RULE_EXECUTION]: [], + }); + }); + it('should not return requests property when not enabled', async () => { const { logs } = await previewRule({ supertest, @@ -1463,6 +1471,35 @@ export default ({ getService }: FtrProviderContext) => { 'POST /ecs_compliant/_search?ignore_unavailable=true' ); }); + it('should not return requests with any data tier filter', async () => { + const { logs } = await previewRule({ + supertest, + rule, + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + enableLoggedRequests: true, + }); + + const requests = logs[0].requests; + + expect(requests![0].request).not.toContain('data_frozen'); + }); + it('should return requests with included data tiers filters from advanced settings', async () => { + await setAdvancedSettings(supertest, { + [EXCLUDED_DATA_TIERS_FOR_RULE_EXECUTION]: ['data_frozen'], + }); + const { logs } = await previewRule({ + supertest, + rule, + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + enableLoggedRequests: true, + }); + + const requests = logs[0].requests; + + expect(requests![0].request).toMatch( + /"must_not":\s*\[\s*{\s*"terms":\s*{\s*"_tier":\s*\[\s*"data_frozen"\s*\]/ + ); + }); }); }); }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts index 5667762ce95c4..2c12400b7f169 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts @@ -24,3 +24,4 @@ export * from './get_stats'; export * from './get_detection_metrics_from_body'; export * from './get_stats_url'; export * from './combine_to_ndjson'; +export * from './set_advanced_settings'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/set_advanced_settings.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/set_advanced_settings.ts new file mode 100644 index 0000000000000..98fe191096253 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/set_advanced_settings.ts @@ -0,0 +1,26 @@ +/* + * 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 { + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; + +import type SuperTest from 'supertest'; + +export const setAdvancedSettings = async ( + supertest: SuperTest.Agent, + settings: Record +) => { + return supertest + .post('/internal/kibana/settings') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send({ changes: settings }) + .expect(200); +};