diff --git a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml index 6679e3006bb00..5a89b3bfb4f3a 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml @@ -19,12 +19,12 @@ spec: description: Run Kibana FIPS smoke tests spec: env: - SLACK_NOTIFICATIONS_CHANNEL: "#kibana-fips-ftr-errors" - ELASTIC_SLACK_NOTIFICATIONS_ENABLED: "true" + SLACK_NOTIFICATIONS_CHANNEL: '#kibana-operations-alerts' + ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'true' repository: elastic/kibana branch_configuration: main default_branch: main - pipeline_file: ".buildkite/pipelines/fips.yml" + pipeline_file: '.buildkite/pipelines/fips.yml' provider_settings: trigger_mode: none schedules: diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts index 132ff6e572dd7..e07737ea60897 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -116,7 +116,7 @@ describe('autocomplete', () => { }, }); - const sourceCommands = ['row', 'from', 'show']; + const sourceCommands = ['row', 'from', 'show', 'metrics']; describe('New command', () => { testSuggestions( @@ -1278,7 +1278,7 @@ describe('autocomplete', () => { // Source command testSuggestions( 'F', - ['FROM $0', 'ROW $0', 'SHOW $0'].map(attachTriggerCommand).map(attachAsSnippet), + ['FROM $0', 'ROW $0', 'SHOW $0', 'METRICS $0'].map(attachTriggerCommand).map(attachAsSnippet), undefined, 1 ); diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts index 4446b4e32908d..0b9f704a43bcc 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -127,7 +127,7 @@ export function isComma(char: string) { } export function isSourceCommand({ label }: { label: string }) { - return ['FROM', 'ROW', 'SHOW'].includes(label); + return ['FROM', 'ROW', 'SHOW', 'METRICS'].includes(label); } let fnLookups: Map | undefined; diff --git a/src/core/server/integration_tests/elasticsearch/version_compatibility.test.ts b/src/core/server/integration_tests/elasticsearch/version_compatibility.test.ts index bfd7575d58283..eb6cc767d5817 100644 --- a/src/core/server/integration_tests/elasticsearch/version_compatibility.test.ts +++ b/src/core/server/integration_tests/elasticsearch/version_compatibility.test.ts @@ -91,8 +91,7 @@ describe('Version Compatibility', () => { await expect(startServers({ customKibanaVersion: previousMinor() })).resolves.toBeUndefined(); }); - // FLAKY: https://github.com/elastic/kibana/issues/171289 - it.skip('should flag the incompatibility on version mismatch (ES is previous minor)', async () => { + it('should flag the incompatibility on version mismatch (ES is previous minor)', async () => { const found$ = new Subject(); consoleSpy.mockImplementation((str) => { if (str.includes('is incompatible')) { diff --git a/test/functional/apps/discover/group1/_discover.ts b/test/functional/apps/discover/group1/_discover.ts index c931187250cc3..e6cf2edca620f 100644 --- a/test/functional/apps/discover/group1/_discover.ts +++ b/test/functional/apps/discover/group1/_discover.ts @@ -216,8 +216,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.update({ 'dateFormat:tz': 'America/Phoenix' }); await PageObjects.common.navigateToApp('discover'); await PageObjects.header.awaitKibanaChrome(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); await queryBar.clearQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); log.debug( 'check that the newest doc timestamp is now -7 hours from the UTC time in the first test' diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts index 31b80b880bcc9..63a9201b1f265 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts @@ -45,7 +45,7 @@ export const defineBulkActionCspBenchmarkRulesRoute = (router: CspRouter) => access: 'internal', path: CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH, options: { - tags: ['access:cloud-security-posture-read'], + tags: ['access:cloud-security-posture-all'], }, }) .addVersion( diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts new file mode 100644 index 0000000000000..050fa67d5cbaf --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts @@ -0,0 +1,27 @@ +/* + * 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 * as t from 'io-ts'; +import { investigationResponseSchema } from './investigation'; + +const createInvestigationParamsSchema = t.type({ + body: t.type({ + id: t.string, + title: t.string, + parameters: t.type({ + timeRange: t.type({ from: t.number, to: t.number }), + }), + }), +}); + +const createInvestigationResponseSchema = investigationResponseSchema; + +type CreateInvestigationInput = t.OutputOf; // Raw payload sent by the frontend +type CreateInvestigationParams = t.TypeOf; // Parsed payload used by the backend +type CreateInvestigationResponse = t.OutputOf; // Raw response sent to the frontend + +export { createInvestigationParamsSchema, createInvestigationResponseSchema }; +export type { CreateInvestigationInput, CreateInvestigationParams, CreateInvestigationResponse }; diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/find.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/find.ts new file mode 100644 index 0000000000000..dc76a39fce679 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/find.ts @@ -0,0 +1,28 @@ +/* + * 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 * as t from 'io-ts'; +import { investigationResponseSchema } from './investigation'; + +const findInvestigationsParamsSchema = t.partial({ + query: t.partial({ + page: t.string, + perPage: t.string, + }), +}); + +const findInvestigationsResponseSchema = t.type({ + page: t.number, + perPage: t.number, + total: t.number, + results: t.array(investigationResponseSchema), +}); + +type FindInvestigationsParams = t.TypeOf; // Parsed payload used by the backend +type FindInvestigationsResponse = t.OutputOf; // Raw response sent to the frontend + +export { findInvestigationsParamsSchema, findInvestigationsResponseSchema }; +export type { FindInvestigationsParams, FindInvestigationsResponse }; diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/get.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/get.ts new file mode 100644 index 0000000000000..b30fb9f61cff8 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/get.ts @@ -0,0 +1,22 @@ +/* + * 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 * as t from 'io-ts'; +import { investigationResponseSchema } from './investigation'; + +const getInvestigationParamsSchema = t.type({ + path: t.type({ + id: t.string, + }), +}); + +const getInvestigationResponseSchema = investigationResponseSchema; + +type GetInvestigationParams = t.TypeOf; // Parsed payload used by the backend +type GetInvestigationResponse = t.OutputOf; // Raw response sent to the frontend + +export { getInvestigationParamsSchema, getInvestigationResponseSchema }; +export type { GetInvestigationParams, GetInvestigationResponse }; diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts new file mode 100644 index 0000000000000..3046a5c4c6d8a --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts @@ -0,0 +1,22 @@ +/* + * 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 * as t from 'io-ts'; + +const investigationResponseSchema = t.type({ + id: t.string, + title: t.string, + createdAt: t.number, + createdBy: t.string, + parameters: t.type({ + timeRange: t.type({ from: t.number, to: t.number }), + }), +}); + +type InvestigationResponse = t.OutputOf; + +export { investigationResponseSchema }; +export type { InvestigationResponse }; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts new file mode 100644 index 0000000000000..f079d922d1a9d --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const investigationSchema = t.type({ + id: t.string, + title: t.string, + createdAt: t.number, + createdBy: t.string, + parameters: t.type({ + timeRange: t.type({ from: t.number, to: t.number }), + }), +}); + +export type Investigation = t.TypeOf; +export type StoredInvestigation = t.OutputOf; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/models/pagination.ts b/x-pack/plugins/observability_solution/investigate_app/server/models/pagination.ts new file mode 100644 index 0000000000000..255614932fe5e --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/server/models/pagination.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. + */ + +export interface Paginated { + total: number; + page: number; + perPage: number; + results: T[]; +} + +export interface Pagination { + page: number; + perPage: number; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/server/plugin.ts b/x-pack/plugins/observability_solution/investigate_app/server/plugin.ts index 7b8a1772858ec..f1ee1cacd155b 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/plugin.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/plugin.ts @@ -17,6 +17,8 @@ import type { InvestigateAppSetupDependencies, InvestigateAppStartDependencies, } from './types'; +import { investigation } from './saved_objects/investigation'; +import { InvestigateAppConfig } from './config'; export class InvestigateAppPlugin implements @@ -28,9 +30,11 @@ export class InvestigateAppPlugin > { logger: Logger; + config: InvestigateAppConfig; constructor(context: PluginInitializerContext) { this.logger = context.logger.get(); + this.config = context.config.get(); } setup( coreSetup: CoreSetup, @@ -47,13 +51,17 @@ export class InvestigateAppPlugin }; }) as InvestigateAppRouteHandlerResources['plugins']; - registerServerRoutes({ - core: coreSetup, - logger: this.logger, - dependencies: { - plugins: routeHandlerPlugins, - }, - }); + if (this.config.enabled === true) { + coreSetup.savedObjects.registerType(investigation); + + registerServerRoutes({ + core: coreSetup, + logger: this.logger, + dependencies: { + plugins: routeHandlerPlugins, + }, + }); + } return {}; } diff --git a/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts b/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts index 63931f717385c..7565330316fed 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts @@ -5,8 +5,63 @@ * 2.0. */ +import { findInvestigationsParamsSchema } from '../../common/schema/find'; +import { createInvestigationParamsSchema } from '../../common/schema/create'; +import { createInvestigation } from '../services/create_investigation'; +import { investigationRepositoryFactory } from '../services/investigation_repository'; +import { createInvestigateAppServerRoute } from './create_investigate_app_server_route'; +import { findInvestigations } from '../services/find_investigations'; +import { getInvestigationParamsSchema } from '../../common/schema/get'; +import { getInvestigation } from '../services/get_investigation'; + +const createInvestigationRoute = createInvestigateAppServerRoute({ + endpoint: 'POST /api/observability/investigations 2023-10-31', + options: { + tags: [], + }, + params: createInvestigationParamsSchema, + handler: async (params) => { + const soClient = (await params.context.core).savedObjects.client; + const repository = investigationRepositoryFactory({ soClient, logger: params.logger }); + + return await createInvestigation(params.params.body, repository); + }, +}); + +const findInvestigationsRoute = createInvestigateAppServerRoute({ + endpoint: 'GET /api/observability/investigations 2023-10-31', + options: { + tags: [], + }, + params: findInvestigationsParamsSchema, + handler: async (params) => { + const soClient = (await params.context.core).savedObjects.client; + const repository = investigationRepositoryFactory({ soClient, logger: params.logger }); + + return await findInvestigations(params.params?.query ?? {}, repository); + }, +}); + +const getInvestigationRoute = createInvestigateAppServerRoute({ + endpoint: 'GET /api/observability/investigations/{id} 2023-10-31', + options: { + tags: [], + }, + params: getInvestigationParamsSchema, + handler: async (params) => { + const soClient = (await params.context.core).savedObjects.client; + const repository = investigationRepositoryFactory({ soClient, logger: params.logger }); + + return await getInvestigation(params.params.path, repository); + }, +}); + export function getGlobalInvestigateAppServerRouteRepository() { - return {}; + return { + ...createInvestigationRoute, + ...findInvestigationsRoute, + ...getInvestigationRoute, + }; } export type InvestigateAppServerRouteRepository = ReturnType< diff --git a/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts new file mode 100644 index 0000000000000..47fa9f17749c1 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts @@ -0,0 +1,33 @@ +/* + * 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 { SavedObjectsType } from '@kbn/core-saved-objects-server'; +import { SavedObject } from '@kbn/core/server'; +import { StoredInvestigation } from '../models/investigation'; + +export const SO_INVESTIGATION_TYPE = 'investigation'; + +export const investigation: SavedObjectsType = { + name: SO_INVESTIGATION_TYPE, + hidden: false, + namespaceType: 'multiple-isolated', + switchToModelVersionAt: '8.10.0', + mappings: { + dynamic: false, + properties: { + id: { type: 'keyword' }, + title: { type: 'text' }, + }, + }, + management: { + displayName: 'Investigation', + importableAndExportable: false, + getTitle(savedObject: SavedObject) { + return `Investigation: [${savedObject.attributes.title}]`; + }, + }, +}; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts new file mode 100644 index 0000000000000..9d28136c06f6c --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts @@ -0,0 +1,19 @@ +/* + * 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 { CreateInvestigationInput, CreateInvestigationResponse } from '../../common/schema/create'; +import { InvestigationRepository } from './investigation_repository'; + +export async function createInvestigation( + params: CreateInvestigationInput, + repository: InvestigationRepository +): Promise { + const investigation = { ...params, createdAt: Date.now(), createdBy: 'elastic' }; + await repository.save(investigation); + + return investigation; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts new file mode 100644 index 0000000000000..2c08125aff734 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts @@ -0,0 +1,31 @@ +/* + * 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 { + FindInvestigationsParams, + FindInvestigationsResponse, + findInvestigationsResponseSchema, +} from '../../common/schema/find'; +import { InvestigationRepository } from './investigation_repository'; + +export async function findInvestigations( + params: FindInvestigationsParams, + repository: InvestigationRepository +): Promise { + const investigations = await repository.search(toPagination(params)); + + return findInvestigationsResponseSchema.encode(investigations); +} + +function toPagination(params: FindInvestigationsParams) { + const DEFAULT_PER_PAGE = 10; + const DEFAULT_PAGE = 1; + return { + page: params.page ? parseInt(params.page, 10) : DEFAULT_PAGE, + perPage: params.perPage ? parseInt(params.perPage, 10) : DEFAULT_PER_PAGE, + }; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/get_investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/get_investigation.ts new file mode 100644 index 0000000000000..9bd6025f8e8a2 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/get_investigation.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 { GetInvestigationParams, GetInvestigationResponse } from '../../common/schema/get'; +import { InvestigationRepository } from './investigation_repository'; + +export async function getInvestigation( + params: GetInvestigationParams, + repository: InvestigationRepository +): Promise { + const investigation = await repository.findById(params.id); + + return investigation; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts new file mode 100644 index 0000000000000..6d9c5ddbc0d03 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts @@ -0,0 +1,109 @@ +/* + * 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 { Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import { isLeft } from 'fp-ts/lib/Either'; +import { Investigation, StoredInvestigation, investigationSchema } from '../models/investigation'; +import { SO_INVESTIGATION_TYPE } from '../saved_objects/investigation'; +import { Paginated, Pagination } from '../models/pagination'; + +export interface InvestigationRepository { + save(investigation: Investigation): Promise; + findById(id: string): Promise; + deleteById(id: string): Promise; + search(pagination: Pagination): Promise>; +} + +export function investigationRepositoryFactory({ + soClient, + logger, +}: { + soClient: SavedObjectsClientContract; + logger: Logger; +}): InvestigationRepository { + function toInvestigation(stored: StoredInvestigation): Investigation | undefined { + const result = investigationSchema.decode({ + ...stored, + }); + + if (isLeft(result)) { + logger.error(`Invalid stored Investigation with id [${stored.id}]`); + return undefined; + } + + return result.right; + } + + function toStoredInvestigation(investigation: Investigation): StoredInvestigation { + return investigationSchema.encode(investigation); + } + + return { + async save(investigation: Investigation): Promise { + await soClient.create( + SO_INVESTIGATION_TYPE, + toStoredInvestigation(investigation), + { + id: investigation.id, + overwrite: true, + } + ); + }, + + async findById(id: string): Promise { + const response = await soClient.find({ + type: SO_INVESTIGATION_TYPE, + page: 1, + perPage: 1, + filter: `investigation.attributes.id:(${id})`, + }); + + if (response.total === 0) { + throw new Error(`Investigation [${id}] not found`); + } + + const investigation = toInvestigation(response.saved_objects[0].attributes); + if (investigation === undefined) { + throw new Error('Invalid stored Investigation'); + } + + return investigation; + }, + + async deleteById(id: string): Promise { + const response = await soClient.find({ + type: SO_INVESTIGATION_TYPE, + page: 1, + perPage: 1, + filter: `investigation.attributes.id:(${id})`, + }); + + if (response.total === 0) { + throw new Error(`Investigation [${id}] not found`); + } + + await soClient.delete(SO_INVESTIGATION_TYPE, response.saved_objects[0].id); + }, + + async search(pagination: Pagination): Promise> { + const response = await soClient.find({ + type: SO_INVESTIGATION_TYPE, + page: pagination.page, + perPage: pagination.perPage, + }); + + return { + total: response.total, + perPage: response.per_page, + page: response.page, + results: response.saved_objects + .map((savedObject) => toInvestigation(savedObject.attributes)) + .filter((investigation) => investigation !== undefined) as Investigation[], + }; + }, + }; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json index e5a4e73d4990b..b4b586601ebaa 100644 --- a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json +++ b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json @@ -51,5 +51,6 @@ "@kbn/ui-actions-plugin", "@kbn/esql-datagrid", "@kbn/server-route-repository-utils", + "@kbn/core-saved-objects-server", ], } diff --git a/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/hooks/use_filter_update.test.ts b/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/hooks/use_filter_update.test.ts index da3a25a5fc9df..734b018a6b624 100644 --- a/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/hooks/use_filter_update.test.ts +++ b/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/hooks/use_filter_update.test.ts @@ -4,10 +4,39 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { addUpdatedField } from './use_filter_update'; +import { renderHook } from '@testing-library/react-hooks'; +import { addUpdatedField, useFilterUpdate } from './use_filter_update'; +import * as params from './use_url_params'; describe('useFilterUpdate', () => { + describe('useFilterUpdate hook', () => { + let getUrlParamsSpy; + let updateUrlSpy: jest.Mock; + + beforeEach(() => { + getUrlParamsSpy = jest.fn().mockReturnValue({ + filters: '[["testField",["tag1"]]]', + excludedFilters: '[["testField",["tag2"]]]', + }); + updateUrlSpy = jest.fn(); + jest.spyOn(params, 'useUrlParams').mockReturnValue([getUrlParamsSpy, updateUrlSpy]); + }); + + it('does not update url when filters have not been updated', () => { + renderHook(() => useFilterUpdate('testField', ['tag1'], ['tag2'])); + expect(updateUrlSpy).not.toBeCalled(); + }); + + it('does update url when filters have been updated', () => { + renderHook(() => useFilterUpdate('testField', ['tag1', 'tag2'], [])); + expect(updateUrlSpy).toBeCalledWith({ + filters: '[["testField",["tag1","tag2"]]]', + excludedFilters: '', + pagination: '', + }); + }); + }); + describe('addUpdatedField', () => { it('conditionally adds fields if they are new', () => { const testVal = {}; diff --git a/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/hooks/use_filter_update.ts b/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/hooks/use_filter_update.ts index 5578230ab2cf0..498cdcda93f3b 100644 --- a/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/hooks/use_filter_update.ts +++ b/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/hooks/use_filter_update.ts @@ -62,6 +62,11 @@ export const useFilterUpdate = ( const newFiltersString = getUpdateFilters(currentFiltersMap, fieldName, values); const newExclusionsString = getUpdateFilters(currentExclusionsMap, fieldName, notValues); + // no new filters to apply + if (filters === newFiltersString && excludedFilters === newExclusionsString) { + return; + } + const update: { [key: string]: string } = {}; addUpdatedField(filters, 'filters', newFiltersString, update); diff --git a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts index 54ae003de8698..5b80b5c7bc99d 100644 --- a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts +++ b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts @@ -484,8 +484,8 @@ export default function (providerContext: FtrProviderContext) { }); expect(status).to.be(403); }); - // Blocked by https://github.com/elastic/kibana/issues/188059 - it.skip('users with read privileges on cloud security should be able to mute', async () => { + + it('users with all privileges on cloud security should be able to mute', async () => { const rule1 = await getRandomCspBenchmarkRule(); const rule2 = await getRandomCspBenchmarkRule(); @@ -494,7 +494,7 @@ export default function (providerContext: FtrProviderContext) { .set(ELASTIC_HTTP_VERSION_HEADER, '1') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .set('kbn-xsrf', 'xxxx') - .auth('role_security_read_user', cspSecurity.getPasswordForUser('role_security_read_user')) + .auth('role_security_all_user', cspSecurity.getPasswordForUser('role_security_all_user')) .send({ action: 'mute', rules: [ diff --git a/x-pack/test/cloud_security_posture_api/routes/helper/user_roles_utilites.ts b/x-pack/test/cloud_security_posture_api/routes/helper/user_roles_utilites.ts index ef66b58d28311..aac6b19ddbef6 100644 --- a/x-pack/test/cloud_security_posture_api/routes/helper/user_roles_utilites.ts +++ b/x-pack/test/cloud_security_posture_api/routes/helper/user_roles_utilites.ts @@ -129,6 +129,24 @@ export function CspSecurityCommonProvider(providerContext: FtrProviderContext) { }, ], }, + { + name: 'role_security_all', + elasticsearch: { + indices: securityUserIndinces, + }, + kibana: [ + { + base: [], + feature: { + siem: ['all'], + fleet: ['all'], + fleetv2: ['all'], + savedObjectsManagement: ['all'], + }, + spaces: ['*'], + }, + ], + }, ]; const users = [ @@ -140,7 +158,7 @@ export function CspSecurityCommonProvider(providerContext: FtrProviderContext) { }, { name: 'role_security_read_user_alerts', - full_name: 'user with 0 security privilege for', + full_name: 'user with 0 security privilege', password: 'csp123', roles: ['role_security_read_alerts'], }, @@ -152,10 +170,16 @@ export function CspSecurityCommonProvider(providerContext: FtrProviderContext) { }, { name: 'role_security_no_read_user_alerts', - full_name: 'user with 0 security privilege for', + full_name: 'user with 0 security privilege', password: 'csp123', roles: ['role_security_no_read_alerts'], }, + { + name: 'role_security_all_user', + full_name: 'user with all security privilege', + password: 'csp123', + roles: ['role_security_all'], + }, ]; return { diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover.ts index 8567b292b2407..531202481ba84 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover.ts @@ -216,15 +216,19 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/189943 - // FLAKY: https://github.com/elastic/kibana/issues/190058 - describe.skip('time zone switch', () => { + describe('time zone switch', () => { it('should show bars in the correct time zone after switching', async function () { await kibanaServer.uiSettings.update({ 'dateFormat:tz': 'America/Phoenix' }); await PageObjects.common.navigateToApp('discover'); await PageObjects.header.awaitKibanaChrome(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); await queryBar.clearQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); log.debug( 'check that the newest doc timestamp is now -7 hours from the UTC time in the first test'