diff --git a/src/platform/packages/shared/kbn-management/settings/setting_ids/index.ts b/src/platform/packages/shared/kbn-management/settings/setting_ids/index.ts index e76139cb86672..3e35052caf393 100644 --- a/src/platform/packages/shared/kbn-management/settings/setting_ids/index.ts +++ b/src/platform/packages/shared/kbn-management/settings/setting_ids/index.ts @@ -126,6 +126,8 @@ export const OBSERVABILITY_AI_ASSISTANT_SEARCH_CONNECTOR_INDEX_PATTERN = 'observability:aiAssistantSearchConnectorIndexPattern'; export const OBSERVABILITY_SEARCH_EXCLUDED_DATA_TIERS = 'observability:searchExcludedDataTiers'; export const OBSERVABILITY_ENABLE_STREAMS_UI = 'observability:enableStreamsUI'; +export const OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS = + 'observability:streamsEnableSignificantEvents'; // Reporting settings export const XPACK_REPORTING_CUSTOM_PDF_LOGO_ID = 'xpackReporting:customPdfLogo'; diff --git a/src/platform/packages/shared/serverless/settings/observability_project/index.ts b/src/platform/packages/shared/serverless/settings/observability_project/index.ts index 419f532e3c8f2..66b1b5f23b29a 100644 --- a/src/platform/packages/shared/serverless/settings/observability_project/index.ts +++ b/src/platform/packages/shared/serverless/settings/observability_project/index.ts @@ -24,6 +24,7 @@ export const OBSERVABILITY_PROJECT_SETTINGS = [ settings.OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE, settings.OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID, settings.OBSERVABILITY_ENABLE_STREAMS_UI, + settings.OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS, ]; export const OBSERVABILITY_AI_ASSISTANT_PROJECT_SETTINGS = [ diff --git a/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/schema.ts b/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/schema.ts index a4e246edd1096..4e6530393eed0 100644 --- a/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/schema.ts @@ -658,4 +658,10 @@ export const stackManagementSchema: MakeSchemaFrom = { description: 'Enable Streams UI.', }, }, + 'observability:streamsEnableSignificantEvents': { + type: 'boolean', + _meta: { + description: 'Enable significant events in streams.', + }, + }, }; diff --git a/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/types.ts b/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/types.ts index 81b3c347656e9..fcd913eb2939a 100644 --- a/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/types.ts @@ -171,4 +171,5 @@ export interface UsageStats { 'securitySolution:maxUnassociatedNotes': number; 'observability:searchExcludedDataTiers': string[]; 'observability:enableStreamsUI': boolean; + 'observability:streamsEnableSignificantEvents': boolean; } diff --git a/src/platform/plugins/shared/telemetry/schema/oss_platform.json b/src/platform/plugins/shared/telemetry/schema/oss_platform.json index 46ea60684aebe..8671a2f0e8367 100644 --- a/src/platform/plugins/shared/telemetry/schema/oss_platform.json +++ b/src/platform/plugins/shared/telemetry/schema/oss_platform.json @@ -11537,6 +11537,12 @@ "_meta": { "description": "Enable Streams UI." } + }, + "observability:streamsEnableSignificantEvents": { + "type": "boolean", + "_meta": { + "description": "Enable significant events in streams." + } } } }, diff --git a/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_cdp_perf.spec.ts b/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_cdp_perf.spec.ts index 82f5ab9764745..4d1ddf644e1d3 100644 --- a/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_cdp_perf.spec.ts +++ b/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_cdp_perf.spec.ts @@ -41,6 +41,7 @@ test.describe( page, pageObjects, perfTracker, + config, }) => { perfTracker.captureBundleResponses(cdp); // Start tracking @@ -73,6 +74,7 @@ test.describe( 'kbn-ui-shared-deps-npm', 'lens', 'maps', + ...(config.projectType === 'security' ? ['securitySolution'] : []), 'unifiedSearch', ]); // Validate individual plugin bundle sizes diff --git a/x-pack/platform/plugins/shared/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap b/x-pack/platform/plugins/shared/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap index d01ad2a14d8fe..4a8749e2ef0c7 100644 --- a/x-pack/platform/plugins/shared/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap +++ b/x-pack/platform/plugins/shared/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap @@ -9979,6 +9979,238 @@ Object { } `; +exports[`Alert as data fields checks detect AAD fields changes for: streams.rules.esql 1`] = ` +Object { + "dynamic": false, + "fieldMap": Object { + "@timestamp": Object { + "array": false, + "required": true, + "type": "date", + }, + "event.action": Object { + "array": false, + "ignore_above": 1024, + "required": false, + "type": "keyword", + }, + "event.kind": Object { + "array": false, + "ignore_above": 1024, + "required": false, + "type": "keyword", + }, + "event.original": Object { + "array": false, + "ignore_above": 1024, + "required": false, + "type": "keyword", + }, + "kibana.alert.action_group": Object { + "array": false, + "required": false, + "type": "keyword", + }, + "kibana.alert.case_ids": Object { + "array": true, + "required": false, + "type": "keyword", + }, + "kibana.alert.consecutive_matches": Object { + "array": false, + "required": false, + "type": "long", + }, + "kibana.alert.duration.us": Object { + "array": false, + "required": false, + "type": "long", + }, + "kibana.alert.end": Object { + "array": false, + "required": false, + "type": "date", + }, + "kibana.alert.flapping": Object { + "array": false, + "required": false, + "type": "boolean", + }, + "kibana.alert.flapping_history": Object { + "array": true, + "required": false, + "type": "boolean", + }, + "kibana.alert.instance.id": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.intended_timestamp": Object { + "array": false, + "required": false, + "type": "date", + }, + "kibana.alert.last_detected": Object { + "array": false, + "required": false, + "type": "date", + }, + "kibana.alert.maintenance_window_ids": Object { + "array": true, + "required": false, + "type": "keyword", + }, + "kibana.alert.pending_recovered_count": Object { + "array": false, + "required": false, + "type": "long", + }, + "kibana.alert.previous_action_group": Object { + "array": false, + "required": false, + "type": "keyword", + }, + "kibana.alert.reason": Object { + "array": false, + "multi_fields": Array [ + Object { + "flat_name": "kibana.alert.reason.text", + "name": "text", + "type": "match_only_text", + }, + ], + "required": false, + "type": "keyword", + }, + "kibana.alert.rule.category": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.rule.consumer": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.rule.execution.timestamp": Object { + "array": false, + "required": false, + "type": "date", + }, + "kibana.alert.rule.execution.type": Object { + "array": false, + "required": false, + "type": "keyword", + }, + "kibana.alert.rule.execution.uuid": Object { + "array": false, + "required": false, + "type": "keyword", + }, + "kibana.alert.rule.name": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.rule.parameters": Object { + "array": false, + "ignore_above": 4096, + "required": false, + "type": "flattened", + }, + "kibana.alert.rule.producer": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.rule.revision": Object { + "array": false, + "required": true, + "type": "long", + }, + "kibana.alert.rule.rule_type_id": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.rule.tags": Object { + "array": true, + "required": false, + "type": "keyword", + }, + "kibana.alert.rule.uuid": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.severity_improving": Object { + "array": false, + "required": false, + "type": "boolean", + }, + "kibana.alert.start": Object { + "array": false, + "required": false, + "type": "date", + }, + "kibana.alert.status": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.time_range": Object { + "array": false, + "format": "epoch_millis||strict_date_optional_time", + "required": false, + "type": "date_range", + }, + "kibana.alert.url": Object { + "array": false, + "ignore_above": 2048, + "index": false, + "required": false, + "type": "keyword", + }, + "kibana.alert.uuid": Object { + "array": false, + "required": true, + "type": "keyword", + }, + "kibana.alert.workflow_assignee_ids": Object { + "array": true, + "required": false, + "type": "keyword", + }, + "kibana.alert.workflow_status": Object { + "array": false, + "required": false, + "type": "keyword", + }, + "kibana.alert.workflow_tags": Object { + "array": true, + "required": false, + "type": "keyword", + }, + "kibana.space_ids": Object { + "array": true, + "required": true, + "type": "keyword", + }, + "kibana.version": Object { + "array": false, + "required": false, + "type": "version", + }, + "tags": Object { + "array": true, + "required": false, + "type": "keyword", + }, + }, +} +`; + exports[`Alert as data fields checks detect AAD fields changes for: transform_health 1`] = ` Object { "fieldMap": Object { diff --git a/x-pack/platform/plugins/shared/alerting/server/integration_tests/alert_as_data_fields.test.ts b/x-pack/platform/plugins/shared/alerting/server/integration_tests/alert_as_data_fields.test.ts index 1490dd63f9f29..862a4c2934c29 100644 --- a/x-pack/platform/plugins/shared/alerting/server/integration_tests/alert_as_data_fields.test.ts +++ b/x-pack/platform/plugins/shared/alerting/server/integration_tests/alert_as_data_fields.test.ts @@ -27,6 +27,7 @@ const ruleTypes: string[] = [ 'xpack.ml.anomaly_detection_alert', 'xpack.ml.anomaly_detection_jobs_health', 'slo.rules.burnRate', + 'streams.rules.esql', 'observability.rules.custom_threshold', 'xpack.uptime.alerts.monitorStatus', 'xpack.uptime.alerts.tlsCertificate', diff --git a/x-pack/platform/plugins/shared/streams/common/config.ts b/x-pack/platform/plugins/shared/streams/common/config.ts index 8ab7d8a77adbd..3371b1b6d8cbc 100644 --- a/x-pack/platform/plugins/shared/streams/common/config.ts +++ b/x-pack/platform/plugins/shared/streams/common/config.ts @@ -7,13 +7,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; -export const configSchema = schema.object({ - experimental: schema.maybe( - schema.object({ - significantEventsEnabled: schema.maybe(schema.boolean({ defaultValue: false })), - }) - ), -}); +export const configSchema = schema.object({}); export type StreamsConfig = TypeOf; diff --git a/x-pack/platform/plugins/shared/streams/server/feature_flags.ts b/x-pack/platform/plugins/shared/streams/server/feature_flags.ts new file mode 100644 index 0000000000000..07370e34907f4 --- /dev/null +++ b/x-pack/platform/plugins/shared/streams/server/feature_flags.ts @@ -0,0 +1,34 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { UiSettingsParams } from '@kbn/core-ui-settings-common'; +import { i18n } from '@kbn/i18n'; +import { OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS } from '@kbn/management-settings-ids'; + +const technicalPreviewLabel = i18n.translate('xpack.streams.technicalPreviewSettingLabel', { + defaultMessage: 'Technical Preview', +}); + +export const featureFlagUiSettings: Record = { + [OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS]: { + category: ['observability'], + name: i18n.translate('xpack.streams.significantEventsSettingsName', { + defaultMessage: 'Streams significant events', + }), + value: false, + description: i18n.translate('xpack.streams.significantEventsSettingsDescription', { + defaultMessage: '{technicalPreviewLabel} Enable streams significant events.', + + values: { technicalPreviewLabel: `[${technicalPreviewLabel}]` }, + }), + type: 'boolean', + schema: schema.boolean(), + requiresPageReload: true, + solution: 'oblt', + }, +}; diff --git a/x-pack/platform/plugins/shared/streams/server/lib/streams/assets/query/query_client.ts b/x-pack/platform/plugins/shared/streams/server/lib/streams/assets/query/query_client.ts index 4ab6898d29d0e..01881b3cf4bc6 100644 --- a/x-pack/platform/plugins/shared/streams/server/lib/streams/assets/query/query_client.ts +++ b/x-pack/platform/plugins/shared/streams/server/lib/streams/assets/query/query_client.ts @@ -12,7 +12,6 @@ import { StreamQuery } from '@kbn/streams-schema'; import { map, partition } from 'lodash'; import pLimit from 'p-limit'; import { QueryLink } from '../../../../../common/assets'; -import { StreamsConfig } from '../../../../../common/config'; import { EsqlRuleParams } from '../../../rules/esql/types'; import { AssetClient, getAssetLinkUuid } from '../asset_client'; import { ASSET_ID, ASSET_TYPE } from '../fields'; @@ -32,31 +31,21 @@ function toQueryLink(query: StreamQuery, stream: string): QueryLink { } export class QueryClient { - private readonly isSignificantEventsEnabled: boolean; - constructor( private readonly dependencies: { assetClient: AssetClient; rulesClient: RulesClient; logger: Logger; - config: StreamsConfig; - } - ) { - this.isSignificantEventsEnabled = - dependencies.config.experimental?.significantEventsEnabled ?? false; - } + }, + private readonly isSignificantEventsEnabled: boolean = false + ) {} public async syncQueries(stream: string, queries: StreamQuery[]) { if (!this.isSignificantEventsEnabled) { - return await this.dependencies.assetClient.syncAssetList( - stream, - queries.map((query) => ({ - [ASSET_ID]: query.id, - [ASSET_TYPE]: 'query' as const, - query, - })), - 'query' + this.dependencies.logger.debug( + `Skipping syncQueries for stream "${stream}" because significant events feature is disabled.` ); + return; } /** @@ -112,27 +101,22 @@ export class QueryClient { } public async upsert(stream: string, query: StreamQuery) { - const { assetClient } = this.dependencies; - if (!this.isSignificantEventsEnabled) { - return await assetClient.linkAsset(stream, { - [ASSET_ID]: query.id, - [ASSET_TYPE]: 'query', - query, - }); + this.dependencies.logger.debug( + `Skipping upsert for stream "${stream}" because significant events feature is disabled.` + ); + return; } await this.bulk(stream, [{ index: query }]); } public async delete(stream: string, queryId: string) { - const { assetClient } = this.dependencies; - if (!this.isSignificantEventsEnabled) { - return await assetClient.unlinkAsset(stream, { - [ASSET_TYPE]: 'query', - [ASSET_ID]: queryId, - }); + this.dependencies.logger.debug( + `Skipping delete for stream "${stream}" because significant events feature is disabled.` + ); + return; } await this.bulk(stream, [{ delete: { id: queryId } }]); @@ -142,33 +126,11 @@ export class QueryClient { stream: string, operations: Array<{ index?: StreamQuery; delete?: { id: string } }> ) { - const { assetClient } = this.dependencies; - if (!this.isSignificantEventsEnabled) { - return await assetClient.bulk( - stream, - operations.map((operation) => { - if (operation.index) { - return { - index: { - asset: { - [ASSET_TYPE]: 'query', - [ASSET_ID]: operation.index.id, - query: operation.index, - }, - }, - }; - } - return { - delete: { - asset: { - [ASSET_TYPE]: 'query', - [ASSET_ID]: operation.delete!.id, - }, - }, - }; - }) + this.dependencies.logger.debug( + `Skipping bulk update for stream "${stream}" because significant events feature is disabled.` ); + return; } const currentQueryLinks = await this.dependencies.assetClient.getAssetLinks(stream, ['query']); diff --git a/x-pack/platform/plugins/shared/streams/server/lib/streams/assets/query/query_service.ts b/x-pack/platform/plugins/shared/streams/server/lib/streams/assets/query/query_service.ts index 0223ef5397579..c7eb52678f776 100644 --- a/x-pack/platform/plugins/shared/streams/server/lib/streams/assets/query/query_service.ts +++ b/x-pack/platform/plugins/shared/streams/server/lib/streams/assets/query/query_service.ts @@ -6,17 +6,16 @@ */ import { CoreSetup, KibanaRequest, Logger } from '@kbn/core/server'; -import { StreamsConfig } from '../../../../../common/config'; +import { OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS } from '@kbn/management-settings-ids'; import { StreamsPluginStartDependencies } from '../../../../types'; +import { createFakeRequestBoundToDefaultSpace } from '../../helpers/fake_request_factory'; import { AssetClient } from '../asset_client'; import { QueryClient } from './query_client'; -import { createFakeRequestBoundToDefaultSpace } from '../../helpers/fake_request_factory'; export class QueryService { constructor( private readonly coreSetup: CoreSetup, - private readonly logger: Logger, - private readonly config: StreamsConfig + private readonly logger: Logger ) {} async getClientWithRequest({ @@ -26,16 +25,23 @@ export class QueryService { request: KibanaRequest; assetClient: AssetClient; }): Promise { - const [_, pluginStart] = await this.coreSetup.getStartServices(); + const [core, pluginStart] = await this.coreSetup.getStartServices(); + + const soClient = core.savedObjects.getScopedClient(request); + const uiSettings = core.uiSettings.asScopedToClient(soClient); + const isSignificantEventsEnabled = + (await uiSettings.get(OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS)) ?? false; const fakeRequest = createFakeRequestBoundToDefaultSpace(request); const rulesClient = await pluginStart.alerting.getRulesClientWithRequest(fakeRequest); - return new QueryClient({ - assetClient, - rulesClient, - config: this.config, - logger: this.logger, - }); + return new QueryClient( + { + assetClient, + rulesClient, + logger: this.logger, + }, + isSignificantEventsEnabled + ); } } diff --git a/x-pack/platform/plugins/shared/streams/server/lib/streams/errors/query_not_found_error.ts b/x-pack/platform/plugins/shared/streams/server/lib/streams/errors/query_not_found_error.ts new file mode 100644 index 0000000000000..bd7fa0048e931 --- /dev/null +++ b/x-pack/platform/plugins/shared/streams/server/lib/streams/errors/query_not_found_error.ts @@ -0,0 +1,15 @@ +/* + * 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 { StatusError } from './status_error'; + +export class QueryNotFoundError extends StatusError { + constructor(message: string) { + super(message, 404); + this.name = 'QueryNotFoundError'; + } +} diff --git a/x-pack/platform/plugins/shared/streams/server/plugin.ts b/x-pack/platform/plugins/shared/streams/server/plugin.ts index 4e9c254b7aba0..5314160c630db 100644 --- a/x-pack/platform/plugins/shared/streams/server/plugin.ts +++ b/x-pack/platform/plugins/shared/streams/server/plugin.ts @@ -31,6 +31,7 @@ import { import { ContentService } from './lib/content/content_service'; import { registerRules } from './lib/rules/register_rules'; import { AssetService } from './lib/streams/assets/asset_service'; +import { QueryService } from './lib/streams/assets/query/query_service'; import { StreamsService } from './lib/streams/service'; import { StreamsTelemetryService } from './lib/telemetry/service'; import { streamsRouteRepository } from './routes'; @@ -40,7 +41,7 @@ import { StreamsPluginStartDependencies, StreamsServer, } from './types'; -import { QueryService } from './lib/streams/assets/query/query_service'; +import { featureFlagUiSettings } from './feature_flags'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface StreamsPluginSetup {} @@ -84,22 +85,19 @@ export class StreamsPlugin this.telemetryService.setup(core.analytics); - const isSignificantEventsEnabled = this.config.experimental?.significantEventsEnabled === true; - const alertingFeatures = isSignificantEventsEnabled - ? STREAMS_RULE_TYPE_IDS.map((ruleTypeId) => ({ - ruleTypeId, - consumers: [STREAMS_CONSUMER], - })) - : []; + const alertingFeatures = STREAMS_RULE_TYPE_IDS.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [STREAMS_CONSUMER], + })); - if (isSignificantEventsEnabled) { - registerRules({ plugins, logger: this.logger.get('rules') }); - } + registerRules({ plugins, logger: this.logger.get('rules') }); + + core.uiSettings.register(featureFlagUiSettings); const assetService = new AssetService(core, this.logger); const streamsService = new StreamsService(core, this.logger, this.isDev); const contentService = new ContentService(core, this.logger); - const queryService = new QueryService(core, this.logger, this.config); + const queryService = new QueryService(core, this.logger); plugins.features.registerKibanaFeature({ id: STREAMS_FEATURE_ID, diff --git a/x-pack/platform/plugins/shared/streams/server/routes/queries/route.ts b/x-pack/platform/plugins/shared/streams/server/routes/queries/route.ts index 70b82edf24d55..f9d03c939cda2 100644 --- a/x-pack/platform/plugins/shared/streams/server/routes/queries/route.ts +++ b/x-pack/platform/plugins/shared/streams/server/routes/queries/route.ts @@ -12,6 +12,7 @@ import { } from '@kbn/streams-schema'; import { z } from '@kbn/zod'; import { STREAMS_API_PRIVILEGES } from '../../../common/constants'; +import { QueryNotFoundError } from '../../lib/streams/errors/query_not_found_error'; import { createServerRoute } from '../create_server_route'; import { assertEnterpriseLicense } from '../utils/assert_enterprise_license'; @@ -134,7 +135,9 @@ const deleteQueryRoute = createServerRoute({ }), }), handler: async ({ params, request, getScopedClients }): Promise => { - const { streamsClient, queryClient, licensing } = await getScopedClients({ request }); + const { streamsClient, queryClient, licensing, assetClient } = await getScopedClients({ + request, + }); await assertEnterpriseLicense(licensing); const { @@ -142,6 +145,12 @@ const deleteQueryRoute = createServerRoute({ } = params; await streamsClient.ensureStream(streamName); + + const queryLink = await assetClient.bulkGetByIds(streamName, 'query', [queryId]); + if (queryLink.length === 0) { + throw new QueryNotFoundError(`Query [${queryId}] not found in stream [${streamName}]`); + } + await queryClient.delete(streamName, queryId); return { diff --git a/x-pack/platform/plugins/shared/streams/tsconfig.json b/x-pack/platform/plugins/shared/streams/tsconfig.json index dcefa9a640572..685d5777011d2 100644 --- a/x-pack/platform/plugins/shared/streams/tsconfig.json +++ b/x-pack/platform/plugins/shared/streams/tsconfig.json @@ -55,6 +55,7 @@ "@kbn/core-http-server-utils", "@kbn/inference-common", "@kbn/lock-manager", + "@kbn/core-ui-settings-common", "@kbn/management-settings-ids" ] } diff --git a/x-pack/platform/plugins/shared/streams_app/common/feature_flags.ts b/x-pack/platform/plugins/shared/streams_app/common/feature_flags.ts index 2c52ec2020c40..cd0b590b6c472 100644 --- a/x-pack/platform/plugins/shared/streams_app/common/feature_flags.ts +++ b/x-pack/platform/plugins/shared/streams_app/common/feature_flags.ts @@ -8,5 +8,3 @@ // add into kibana.dev.yml: feature_flags.overrides.featureFlagsStreams.contentPackUIEnabled: true export const FeatureFlagStreamsContentPackUIEnabled = 'featureFlagsStreams.contentPackUIEnabled'; -export const FeatureFlagStreamsSignificantEventsUIEnabled = - 'featureFlagsStreams.significantEventsUIEnabled'; diff --git a/x-pack/platform/test/alerting_api_integration/spaces_only/tests/alerting/group4/check_registered_rule_types.ts b/x-pack/platform/test/alerting_api_integration/spaces_only/tests/alerting/group4/check_registered_rule_types.ts index 15d79fa0a4f80..0407269f9a7c2 100644 --- a/x-pack/platform/test/alerting_api_integration/spaces_only/tests/alerting/group4/check_registered_rule_types.ts +++ b/x-pack/platform/test/alerting_api_integration/spaces_only/tests/alerting/group4/check_registered_rule_types.ts @@ -46,6 +46,7 @@ export default function createRegisteredRuleTypeTests({ getService }: FtrProvide 'siem.newTermsRule', 'siem.notifications', 'slo.rules.burnRate', + 'streams.rules.esql', 'logs.alert.document.count', 'metrics.alert.inventory.threshold', 'metrics.alert.threshold', diff --git a/x-pack/platform/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts b/x-pack/platform/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts index 95a160d173edf..caf537fe1157b 100644 --- a/x-pack/platform/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts +++ b/x-pack/platform/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts @@ -129,6 +129,7 @@ export default function ({ getService }: FtrProviderContext) { 'alerting:siem.savedQueryRule', 'alerting:siem.thresholdRule', 'alerting:slo.rules.burnRate', + 'alerting:streams.rules.esql', 'alerting:transform_health', 'alerting:xpack.ml.anomaly_detection_alert', 'alerting:xpack.ml.anomaly_detection_jobs_health', diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/queries.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/queries.ts index 8eaaa1de03e06..c91d4d591509f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/queries.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/queries.ts @@ -8,6 +8,8 @@ import expect from '@kbn/expect'; import { Streams } from '@kbn/streams-schema'; import { v4 } from 'uuid'; +import { STREAMS_ESQL_RULE_TYPE_ID } from '@kbn/rule-data-utils'; +import { OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS } from '@kbn/management-settings-ids'; import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { StreamsSupertestRepositoryClient, @@ -20,6 +22,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const roleScopedSupertest = getService('roleScopedSupertest'); const alertingApi = getService('alertingApi'); const samlAuth = getService('samlAuth'); + const kibanaServer = getService('kibanaServer'); let roleAuthc: RoleCredentials; let apiClient: StreamsSupertestRepositoryClient; @@ -41,16 +44,22 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { }, }; - describe('Queries API', () => { + describe('Queries API', function () { before(async () => { roleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); apiClient = await createStreamsRepositoryAdminClient(roleScopedSupertest); await enableStreams(apiClient); + await kibanaServer.uiSettings.update({ + [OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS]: true, + }); }); after(async () => { await disableStreams(apiClient); await samlAuth.invalidateM2mApiKeyWithRoleScope(roleAuthc); + await kibanaServer.uiSettings.update({ + [OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS]: false, + }); }); beforeEach(async () => { @@ -88,16 +97,15 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const getQueriesResponse = await getQueries(apiClient, STREAM_NAME); expect(getQueriesResponse.queries).to.eql(queries); - // TODO: Uncomment when significantEventsEnabled feature flag is removed - // const rules = await alertingApi.searchRules( - // roleAuthc, - // 'alert.attributes.name:OutOfMemoryError' - // ); - // expect(rules.body.data).to.have.length(1); - // expect(rules.body.data[0].rule_type_id).to.eql(STREAMS_ESQL_RULE_TYPE_ID); - // expect(rules.body.data[0].params.query).to.eql( - // `FROM ${STREAM_NAME},${STREAM_NAME}.* METADATA _id, _source | WHERE KQL("""message:'OutOfMemoryError'""")` - // ); + const rules = await alertingApi.searchRules( + roleAuthc, + 'alert.attributes.name:OutOfMemoryError' + ); + expect(rules.body.data).to.have.length(1); + expect(rules.body.data[0].rule_type_id).to.eql(STREAMS_ESQL_RULE_TYPE_ID); + expect(rules.body.data[0].params.query).to.eql( + `FROM ${STREAM_NAME},${STREAM_NAME}.* METADATA _id, _source | WHERE KQL("message:'OutOfMemoryError'")` + ); }); describe('PUT /api/streams/{name}/queries/{queryId}', () => { @@ -124,10 +132,9 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const getQueriesResponse = await getQueries(apiClient, STREAM_NAME); expect(getQueriesResponse.queries).to.eql([query]); - // TODO: Uncomment when significantEventsEnabled feature flag is removed - // const rules = await alertingApi.searchRules(roleAuthc, ''); - // expect(rules.body.data).to.have.length(1); - // expect(rules.body.data[0].name).to.eql(query.title); + const rules = await alertingApi.searchRules(roleAuthc, ''); + expect(rules.body.data).to.have.length(1); + expect(rules.body.data[0].name).to.eql(query.title); }); it('updates the query and create a new rule when updating an existing query kql', async () => { @@ -141,7 +148,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { dashboards: [], queries: [query], }); - // const initialRules = await alertingApi.searchRules(roleAuthc, ''); + const initialRules = await alertingApi.searchRules(roleAuthc, ''); const upsertQueryResponse = await apiClient .fetch('PUT /api/streams/{name}/queries/{queryId} 2023-10-31', { @@ -166,11 +173,10 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { }, ]); - // TODO: Uncomment when significantEventsEnabled feature flag is removed - // const updatedRules = await alertingApi.searchRules(roleAuthc, ''); - // expect(updatedRules.body.data).to.have.length(1); - // expect(updatedRules.body.data[0].name).to.eql(query.title); - // expect(updatedRules.body.data[0].id).not.to.eql(initialRules.body.data[0].id); + const updatedRules = await alertingApi.searchRules(roleAuthc, ''); + expect(updatedRules.body.data).to.have.length(1); + expect(updatedRules.body.data[0].name).to.eql(query.title); + expect(updatedRules.body.data[0].id).not.to.eql(initialRules.body.data[0].id); }); it('updates the query and the rule when updating an existing query title', async () => { @@ -184,7 +190,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { dashboards: [], queries: [query], }); - // const initialRules = await alertingApi.searchRules(roleAuthc, ''); + const initialRules = await alertingApi.searchRules(roleAuthc, ''); const upsertQueryResponse = await apiClient .fetch('PUT /api/streams/{name}/queries/{queryId} 2023-10-31', { @@ -209,11 +215,10 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { }, ]); - // TODO: Uncomment when significantEventsEnabled feature flag is removed - // const updatedRules = await alertingApi.searchRules(roleAuthc, ''); - // expect(updatedRules.body.data).to.have.length(1); - // expect(updatedRules.body.data[0].name).to.eql('updated title'); - // expect(updatedRules.body.data[0].id).to.eql(initialRules.body.data[0].id); + const updatedRules = await alertingApi.searchRules(roleAuthc, ''); + expect(updatedRules.body.data).to.have.length(1); + expect(updatedRules.body.data[0].name).to.eql('updated title'); + expect(updatedRules.body.data[0].id).to.eql(initialRules.body.data[0].id); }); }); @@ -242,21 +247,17 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const getQueriesResponse = await getQueries(apiClient, STREAM_NAME); expect(getQueriesResponse.queries).to.eql([]); - // TODO: Uncomment when significantEventsEnabled feature flag is removed - // const rules = await alertingApi.searchRules(roleAuthc, ''); - // expect(rules.body.data).to.have.length(0); + const rules = await alertingApi.searchRules(roleAuthc, ''); + expect(rules.body.data).to.have.length(0); }); - it('throws when deleting an inexistant query', async () => { + it('returns a 404 when deleting an inexistant query', async () => { const queryId = v4(); await apiClient .fetch('DELETE /api/streams/{name}/queries/{queryId} 2023-10-31', { params: { path: { name: STREAM_NAME, queryId } }, }) .expect(404); - - const getQueriesResponse = await getQueries(apiClient, STREAM_NAME); - expect(getQueriesResponse.queries).to.eql([]); }); it('bulks insert and remove queries', async () => { @@ -280,7 +281,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { dashboards: [], queries: [firstQuery, secondQuery, thirdQuery], }); - // const initialRules = await alertingApi.searchRules(roleAuthc, ''); + const initialRules = await alertingApi.searchRules(roleAuthc, ''); const newQuery = { id: 'fourth', @@ -324,22 +325,21 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(bulkResponse).to.have.property('acknowledged', true); const getQueriesResponse = await getQueries(apiClient, STREAM_NAME); - expect(getQueriesResponse.queries).to.eql([firstQuery, newQuery, updateThirdQuery]); - - // TODO: Uncomment when significantEventsEnabled feature flag is removed - // const updatedRules = await alertingApi.searchRules(roleAuthc, ''); - // expect(updatedRules.body.data).to.have.length(3); - // const ruleNames = updatedRules.body.data.map((rule: any) => rule.name); - // expect(ruleNames.includes(firstQuery.title)).to.be(true); - // expect(ruleNames.includes(updateThirdQuery.title)).to.be(true); - // expect(ruleNames.includes(newQuery.title)).to.be(true); - - // const initialThirdRuleId = initialRules.body.data.find( - // (rule: any) => rule.name === thirdQuery.title - // ).id; - // expect(initialThirdRuleId).not.to.eql( - // updatedRules.body.data.find((rule: any) => rule.name === updateThirdQuery.title).id - // ); + expect(getQueriesResponse.queries).to.eql([firstQuery, updateThirdQuery, newQuery]); + + const updatedRules = await alertingApi.searchRules(roleAuthc, ''); + expect(updatedRules.body.data).to.have.length(3); + const ruleNames = updatedRules.body.data.map((rule: any) => rule.name); + expect(ruleNames.includes(firstQuery.title)).to.be(true); + expect(ruleNames.includes(updateThirdQuery.title)).to.be(true); + expect(ruleNames.includes(newQuery.title)).to.be(true); + + const initialThirdRuleId = initialRules.body.data.find( + (rule: any) => rule.name === thirdQuery.title + ).id; + expect(initialThirdRuleId).not.to.eql( + updatedRules.body.data.find((rule: any) => rule.name === updateThirdQuery.title).id + ); }); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/significant_events.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/significant_events.ts index bed0f57165bda..f3df795fb09b1 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/significant_events.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/significant_events.ts @@ -12,6 +12,7 @@ import { isDslLifecycle, isIlmLifecycle, } from '@kbn/streams-schema'; +import { OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS } from '@kbn/management-settings-ids'; import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { StreamsSupertestRepositoryClient, @@ -22,16 +23,23 @@ import { disableStreams, enableStreams, getStream, putStream } from './helpers/r export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const roleScopedSupertest = getService('roleScopedSupertest'); const esClient = getService('es'); + const kibanaServer = getService('kibanaServer'); let apiClient: StreamsSupertestRepositoryClient; - describe('Significant Events', () => { + describe('Significant Events', function () { before(async () => { apiClient = await createStreamsRepositoryAdminClient(roleScopedSupertest); await enableStreams(apiClient); + await kibanaServer.uiSettings.update({ + [OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS]: true, + }); }); after(async () => { await disableStreams(apiClient); + await kibanaServer.uiSettings.update({ + [OBSERVABILITY_STREAMS_ENABLE_SIGNIFICANT_EVENTS]: false, + }); }); describe('Wired streams update', () => { diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 679e0838cb70a..a6db6f46189aa 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -168,6 +168,7 @@ "@kbn/test-suites-xpack-platform", "@kbn/core-chrome-browser", "@kbn/event-log-plugin", - "@kbn/intercepts-plugin" + "@kbn/management-settings-ids", + "@kbn/intercepts-plugin", ] }