diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1b9c828de461c..06f8a9c6d05a1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -831,7 +831,9 @@ x-pack/packages/observability/alerting_rule_utils @elastic/obs-ux-management-tea x-pack/packages/observability/alerting_test_data @elastic/obs-ux-management-team x-pack/packages/observability/get_padded_alert_time_range_util @elastic/obs-ux-management-team x-pack/packages/observability/logs_overview @elastic/obs-ux-logs-team -x-pack/packages/observability/observability_utils @elastic/observability-ui +x-pack/packages/observability/observability_utils/observability_utils_browser @elastic/observability-ui +x-pack/packages/observability/observability_utils/observability_utils_common @elastic/observability-ui +x-pack/packages/observability/observability_utils/observability_utils_server @elastic/observability-ui x-pack/packages/observability/synthetics_test_data @elastic/obs-ux-management-team x-pack/packages/rollup @elastic/kibana-management x-pack/packages/search/shared_ui @elastic/search-kibana diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 737eedabadfa0..8ed73aa521aff 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,37 +5,26 @@ Summarize your PR. If it involves visual changes include a screenshot or gif. ### Checklist -Delete any items that are not applicable to this PR. +Check the PR satisfies following conditions. + +Reviewers should verify this PR satisfies this list as well. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios -- [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed -- [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) -- [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) -- [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) -- [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) - - -### Risk Matrix - -Delete this section if it is not applicable to this PR. +- [ ] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. +- [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed +- [ ] The PR description includes the appropriate Release Notes section, and the correct `release_node:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) -Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. +### Identify risks -When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: +Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss. -| Risk | Probability | Severity | Mitigation/Notes | -|---------------------------|-------------|----------|-------------------------| -| Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | -| Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | -| Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | -| [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | +Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging. +- [ ] [See some risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) +- [ ] ... -### For maintainers -- [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) -- [ ] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index cd18582a7af6c..0c9bd6ada3904 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -85,6 +85,48 @@ include::upgrade-notes.asciidoc[] For information about the {kib} 8.16.0 release, review the following information. +The 8.16.0 release includes the following known issues. + +[float] +[[known-issues-8.16.0]] +=== Known issues + +[discrete] +[[known-199902]] +.Stack Monitoring shows "Unable to load page error" +[%collapsible] +==== +*Details* + +The Stack Monitoring pages Overview, Nodes, Logs can stop working with the error "Unable to load page error". The Stack trace mentions `TypeError: Cannot read properties of undefined (reading 'logsLocator')`. + +*Workaround* + +Disabling the `Set feature visibility > Logs` feature at Kibana Space settings level will prevent the error to occur. Please note the `Logs` feature will not be available on such space. + +It's also possible to `Observability > Logs` feature privilege to `None` on the role level - this will hide the `Logs` feature for individual users and prevent the error for these users as well. + +For more information, refer to {kibana-issue}199902[#199902]. +==== + +[discrete] +[[known-199891-199892]] +.Onboarding, tutorial of APM and OpenTelemetry and some "Beats Only" integrations will show the error "Unable to load page error" +[%collapsible] +==== +*Details* + +Tutorials linked from the {kib} home page show an error "Unable to load page error". The Stack trace mentions `The above error occurred in tutorial_TutorialUi`. + +*Workaround* + +The APM / OpenTelemetry tutorials represented a shortcut to get important parameters to use in the configuration files quickly. +It is still possible to obtain the same parameters following the documentation tutorials of APM. + +More information can be found in the {observability-guide}/apm-collect-application-data.html[APM documentation] and the {observability-guide}/get-started-with-fleet-apm-server.html[Fleet documentation]. + +For information about how to create APM API keys, please check the {observability-guide}/apm-api-key.html#apm-create-an-api-key[API key documentation]. + + +For more information, refer to {kibana-issue}199891[#199891] and {kibana-issue}199892[#199892]. +==== + [float] [[deprecations-8.16.0]] === Deprecations diff --git a/package.json b/package.json index e2491ea76b89b..fb6b8b093560c 100644 --- a/package.json +++ b/package.json @@ -702,7 +702,9 @@ "@kbn/observability-plugin": "link:x-pack/plugins/observability_solution/observability", "@kbn/observability-shared-plugin": "link:x-pack/plugins/observability_solution/observability_shared", "@kbn/observability-synthetics-test-data": "link:x-pack/packages/observability/synthetics_test_data", - "@kbn/observability-utils": "link:x-pack/packages/observability/observability_utils", + "@kbn/observability-utils-browser": "link:x-pack/packages/observability/observability_utils/observability_utils_browser", + "@kbn/observability-utils-common": "link:x-pack/packages/observability/observability_utils/observability_utils_common", + "@kbn/observability-utils-server": "link:x-pack/packages/observability/observability_utils/observability_utils_server", "@kbn/oidc-provider-plugin": "link:x-pack/test/security_api_integration/plugins/oidc_provider", "@kbn/open-telemetry-instrumented-plugin": "link:test/common/plugins/otel_metrics", "@kbn/openapi-common": "link:packages/kbn-openapi-common", diff --git a/packages/kbn-apm-utils/index.ts b/packages/kbn-apm-utils/index.ts index 7ada02fe8173e..4d551c3b9f037 100644 --- a/packages/kbn-apm-utils/index.ts +++ b/packages/kbn-apm-utils/index.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import agent from 'elastic-apm-node'; +import agent, { Logger } from 'elastic-apm-node'; import asyncHooks from 'async_hooks'; export interface SpanOptions { @@ -34,14 +34,48 @@ const runInNewContext = any>(cb: T): ReturnType( optionsOrName: SpanOptions | string, - cb: (span?: Span) => Promise + cb: (span?: Span) => Promise, + logger?: Logger ): Promise { const options = parseSpanOptions(optionsOrName); const { name, type, subtype, labels, intercept } = options; + let time: number | undefined; + if (logger?.isLevelEnabled('debug')) { + time = performance.now(); + } + + function logTook(failed: boolean) { + if (time) { + logger?.debug( + () => + `Operation ${name}${failed ? ` (failed)` : ''} ${ + Math.round(performance.now() - time!) / 1000 + }s` + ); + } + } + + const withLogTook = [ + (res: TR): TR | Promise => { + logTook(false); + return res; + }, + (err: any): never => { + logTook(true); + throw err; + }, + ]; + if (!agent.isStarted()) { - return cb(); + const promise = cb(); + // make sure tests that mock out the callback with a sync + // function don't fail. + if (typeof promise === 'object' && 'then' in promise) { + return promise.then(...withLogTook); + } + return promise; } let createdSpan: Span | undefined; @@ -57,7 +91,7 @@ export async function withSpan( createdSpan = agent.startSpan(name) ?? undefined; if (!createdSpan) { - return cb(); + return cb().then(...withLogTook); } } @@ -76,7 +110,7 @@ export async function withSpan( } if (!span) { - return promise; + return promise.then(...withLogTook); } const targetedSpan = span; @@ -98,6 +132,7 @@ export async function withSpan( } return promise + .then(...withLogTook) .then((res) => { if (!targetedSpan.outcome || targetedSpan.outcome === 'unknown') { targetedSpan.outcome = 'success'; diff --git a/packages/kbn-flot-charts/lib/jquery_flot.js b/packages/kbn-flot-charts/lib/jquery_flot.js index 3b13b317c616c..3087a59acdf77 100644 --- a/packages/kbn-flot-charts/lib/jquery_flot.js +++ b/packages/kbn-flot-charts/lib/jquery_flot.js @@ -2711,110 +2711,135 @@ Licensed under the MIT license. function insertLegend() { - if (options.legend.container != null) { - $(options.legend.container).html(""); - } else { - placeholder.find(".legend").remove(); - } - - if (!options.legend.show) { - return; - } - - var fragments = [], entries = [], rowStarted = false, - lf = options.legend.labelFormatter, s, label; - - // Build a list of legend entries, with each having a label and a color - - for (var i = 0; i < series.length; ++i) { - s = series[i]; - if (s.label) { - label = lf ? lf(s.label, s) : s.label; - if (label) { - entries.push({ - label: label, - color: s.color - }); - } - } - } - - // Sort the legend using either the default or a custom comparator - - if (options.legend.sorted) { - if ($.isFunction(options.legend.sorted)) { - entries.sort(options.legend.sorted); - } else if (options.legend.sorted == "reverse") { - entries.reverse(); - } else { - var ascending = options.legend.sorted != "descending"; - entries.sort(function(a, b) { - return a.label == b.label ? 0 : ( - ((a.label < b.label) != ascending ? 1 : -1) // Logical XOR - ); - }); - } - } - - // Generate markup for the list of entries, in their final order - - for (var i = 0; i < entries.length; ++i) { - - var entry = entries[i]; - - if (i % options.legend.noColumns == 0) { - if (rowStarted) - fragments.push(''); - fragments.push(''); - rowStarted = true; - } - - fragments.push( - '
' + - '' + entry.label + '' - ); - } - - if (rowStarted) - fragments.push(''); - - if (fragments.length == 0) - return; - - var table = '' + fragments.join("") + '
'; - if (options.legend.container != null) - $(options.legend.container).html(table); - else { - var pos = "", - p = options.legend.position, - m = options.legend.margin; - if (m[0] == null) - m = [m, m]; - if (p.charAt(0) == "n") - pos += 'top:' + (m[1] + plotOffset.top) + 'px;'; - else if (p.charAt(0) == "s") - pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;'; - if (p.charAt(1) == "e") - pos += 'right:' + (m[0] + plotOffset.right) + 'px;'; - else if (p.charAt(1) == "w") - pos += 'left:' + (m[0] + plotOffset.left) + 'px;'; - var legend = $('
' + table.replace('style="', 'style="position:absolute;' + pos +';') + '
').appendTo(placeholder); - if (options.legend.backgroundOpacity != 0.0) { - // put in the transparent background - // separately to avoid blended labels and - // label boxes - var c = options.legend.backgroundColor; - if (c == null) { - c = options.grid.backgroundColor; - if (c && typeof c == "string") - c = $.color.parse(c); - else - c = $.color.extract(legend, 'background-color'); - c.a = 1; - c = c.toString(); - } - var div = legend.children(); - $('
').prependTo(legend).css('opacity', options.legend.backgroundOpacity); + if (options.legend.container != null) { + $.find(options.legend.container).html(""); + } else { + placeholder.find(".legend").remove(); + } + + if (!options.legend.show) { + return; + } + + var entries = [], lf = options.legend.labelFormatter, s, label, i; + + // Build a list of legend entries, with each having a label and a color + for (i = 0; i < series.length; ++i) { + s = series[i]; + if (s.label) { + label = lf ? lf(s.label, s) : s.label; + if (label) { + entries.push({ + label: label, + color: s.color + }); + } + } + } + + // No entries implies no legend + if (entries.length === 0) { + return; + } + + // Sort the legend using either the default or a custom comparator + if (options.legend.sorted) { + if ($.isFunction(options.legend.sorted)) { + entries.sort(options.legend.sorted); + } else if (options.legend.sorted === "reverse") { + entries.reverse(); + } else { + var ascending = options.legend.sorted !== "descending"; + entries.sort(function(a, b) { + return a.label === b.label ? 0 : ( + (a.label < b.label) !== ascending ? 1 : -1 // Logical XOR + ); + }); + } + } + + // Generate markup for the list of entries, in their final order + var table = $("
").css({ + "font-size": "smaller", + "color": options.grid.color + }), rowBuffer = null; + + for (i = 0; i < entries.length; ++i) { + + var entry = entries[i]; + + if (i % options.legend.noColumns === 0) { + if (rowBuffer !== null) { + table.append(rowBuffer); + } + rowBuffer = $(""); + } + + var colorbox = $("
").css({ + "width": "4px", + "height": 0, + "border": "5px solid " + entry.color, + "overflow": "hidden" + }), + + borderbox = $("
").css({ + "border": "1px solid " + options.legend.labelBoxBorderColor, + "padding": "1px" + }); + + rowBuffer.append( + $("").addClass("legendColorBox").append(borderbox.append(colorbox)), + $("").addClass("legendLabel").html(entry.label) + ); + } + + table.append(rowBuffer); + + if (options.legend.container != null) { + $(options.legend.container).html(table); + } else { + var pos = { "position": "absolute" }, + p = options.legend.position, + m = options.legend.margin; + if (m[0] == null) { + m = [m, m]; + } + if (p.charAt(0) === "n") { + pos.top = (m[1] + plotOffset.top) + "px"; + } else if (p.charAt(0) === "s") { + pos.bottom = (m[1] + plotOffset.bottom) + "px"; + } + if (p.charAt(1) === "e") { + pos.right = (m[0] + plotOffset.right) + "px"; + } else if (p.charAt(1) === "w") { + pos.left = (m[0] + plotOffset.left) + "px"; + } + var legend = $("
").addClass("legend").append(table.css(pos)).appendTo(placeholder); + if (options.legend.backgroundOpacity !== 0.0) { + + // put in the transparent background + // separately to avoid blended labels and + // label boxes + var c = options.legend.backgroundColor; + if (c == null) { + c = options.grid.backgroundColor; + if (c && typeof c === "string") { + c = $.color.parse(c); + } else { + c = $.color.extract(legend, "background-color"); + } + c.a = 1; + c = c.toString(); + } + var div = legend.children(); + + // Position also applies to this + $("
").css(pos).css({ + "width": div.width() + "px", + "height": div.height() + "px", + "background-color": c, + "opacity": options.legend.backgroundOpacity + }).prependTo(legend); } } } diff --git a/tsconfig.base.json b/tsconfig.base.json index e7a64097448ad..223b2d5a58ca2 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1330,8 +1330,12 @@ "@kbn/observability-shared-plugin/*": ["x-pack/plugins/observability_solution/observability_shared/*"], "@kbn/observability-synthetics-test-data": ["x-pack/packages/observability/synthetics_test_data"], "@kbn/observability-synthetics-test-data/*": ["x-pack/packages/observability/synthetics_test_data/*"], - "@kbn/observability-utils": ["x-pack/packages/observability/observability_utils"], - "@kbn/observability-utils/*": ["x-pack/packages/observability/observability_utils/*"], + "@kbn/observability-utils-browser": ["x-pack/packages/observability/observability_utils/observability_utils_browser"], + "@kbn/observability-utils-browser/*": ["x-pack/packages/observability/observability_utils/observability_utils_browser/*"], + "@kbn/observability-utils-common": ["x-pack/packages/observability/observability_utils/observability_utils_common"], + "@kbn/observability-utils-common/*": ["x-pack/packages/observability/observability_utils/observability_utils_common/*"], + "@kbn/observability-utils-server": ["x-pack/packages/observability/observability_utils/observability_utils_server"], + "@kbn/observability-utils-server/*": ["x-pack/packages/observability/observability_utils/observability_utils_server/*"], "@kbn/oidc-provider-plugin": ["x-pack/test/security_api_integration/plugins/oidc_provider"], "@kbn/oidc-provider-plugin/*": ["x-pack/test/security_api_integration/plugins/oidc_provider/*"], "@kbn/open-telemetry-instrumented-plugin": ["test/common/plugins/otel_metrics"], diff --git a/x-pack/packages/ai-infra/inference-common/index.ts b/x-pack/packages/ai-infra/inference-common/index.ts index 502d8e86a0beb..2791896c801ef 100644 --- a/x-pack/packages/ai-infra/inference-common/index.ts +++ b/x-pack/packages/ai-infra/inference-common/index.ts @@ -81,3 +81,5 @@ export { isInferenceInternalError, isInferenceRequestError, } from './src/errors'; + +export { truncateList } from './src/truncate_list'; diff --git a/x-pack/plugins/inference/common/utils/truncate_list.ts b/x-pack/packages/ai-infra/inference-common/src/truncate_list.ts similarity index 100% rename from x-pack/plugins/inference/common/utils/truncate_list.ts rename to x-pack/packages/ai-infra/inference-common/src/truncate_list.ts diff --git a/x-pack/packages/observability/observability_utils/README.md b/x-pack/packages/observability/observability_utils/README.md deleted file mode 100644 index bd74c0bdffb47..0000000000000 --- a/x-pack/packages/observability/observability_utils/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @kbn/observability-utils - -This package contains utilities for Observability plugins. It's a separate package to get out of dependency hell. You can put anything in here that is stateless and has no dependency on other plugins (either directly or via other packages). - -The utility functions should be used via direct imports to minimize impact on bundle size and limit the risk on importing browser code to the server and vice versa. diff --git a/x-pack/packages/observability/observability_utils/chart/utils.ts b/x-pack/packages/observability/observability_utils/observability_utils_browser/chart/utils.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/chart/utils.ts rename to x-pack/packages/observability/observability_utils/observability_utils_browser/chart/utils.ts diff --git a/x-pack/packages/observability/observability_utils/hooks/use_abort_controller.ts b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_abort_controller.ts similarity index 92% rename from x-pack/packages/observability/observability_utils/hooks/use_abort_controller.ts rename to x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_abort_controller.ts index a383e7b81b4d9..de5c70632b233 100644 --- a/x-pack/packages/observability/observability_utils/hooks/use_abort_controller.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_abort_controller.ts @@ -18,6 +18,9 @@ export function useAbortController() { return { signal: controller.signal, + abort: () => { + controller.abort(); + }, refresh: () => { setController(() => new AbortController()); }, diff --git a/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_abortable_async.ts similarity index 69% rename from x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts rename to x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_abortable_async.ts index 477d765ef7a7f..f0d2bf4a05872 100644 --- a/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_abortable_async.ts @@ -17,12 +17,32 @@ export type AbortableAsyncState = (T extends Promise ? State : State) & { refresh: () => void }; +export type AbortableAsyncStateOf> = + T extends AbortableAsyncState ? Awaited : never; + +interface UseAbortableAsyncOptions { + clearValueOnNext?: boolean; + unsetValueOnError?: boolean; + defaultValue?: () => T; + onError?: (error: Error) => void; +} + +export type UseAbortableAsync< + TAdditionalParameters extends Record = {}, + TAdditionalOptions extends Record = {} +> = ( + fn: ({}: { signal: AbortSignal } & TAdditionalParameters) => T | Promise, + deps: any[], + options?: UseAbortableAsyncOptions & TAdditionalOptions +) => AbortableAsyncState; + export function useAbortableAsync( fn: ({}: { signal: AbortSignal }) => T | Promise, deps: any[], - options?: { clearValueOnNext?: boolean; defaultValue?: () => T } + options?: UseAbortableAsyncOptions ): AbortableAsyncState { const clearValueOnNext = options?.clearValueOnNext; + const unsetValueOnError = options?.unsetValueOnError; const controllerRef = useRef(new AbortController()); @@ -43,6 +63,15 @@ export function useAbortableAsync( setError(undefined); } + function handleError(err: Error) { + setError(err); + if (unsetValueOnError) { + setValue(undefined); + } + setLoading(false); + options?.onError?.(err); + } + try { const response = fn({ signal: controller.signal }); if (isPromise(response)) { @@ -52,12 +81,7 @@ export function useAbortableAsync( setError(undefined); setValue(nextValue); }) - .catch((err) => { - setValue(undefined); - if (!controller.signal.aborted) { - setError(err); - } - }) + .catch(handleError) .finally(() => setLoading(false)); } else { setError(undefined); @@ -65,9 +89,7 @@ export function useAbortableAsync( setLoading(false); } } catch (err) { - setValue(undefined); - setError(err); - setLoading(false); + handleError(err); } return () => { diff --git a/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_date_range.ts b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_date_range.ts new file mode 100644 index 0000000000000..941e106247b87 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_date_range.ts @@ -0,0 +1,63 @@ +/* + * 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 { TimeRange } from '@kbn/data-plugin/common'; +import { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +export function useDateRange({ data }: { data: DataPublicPluginStart }): { + timeRange: TimeRange; + absoluteTimeRange: { + start: number; + end: number; + }; + setTimeRange: React.Dispatch>; +} { + const timefilter = data.query.timefilter.timefilter; + + const [timeRange, setTimeRange] = useState(() => timefilter.getTime()); + + const [absoluteTimeRange, setAbsoluteTimeRange] = useState(() => timefilter.getAbsoluteTime()); + + useEffect(() => { + const timeUpdateSubscription = timefilter.getTimeUpdate$().subscribe({ + next: () => { + setTimeRange(() => timefilter.getTime()); + setAbsoluteTimeRange(() => timefilter.getAbsoluteTime()); + }, + }); + + return () => { + timeUpdateSubscription.unsubscribe(); + }; + }, [timefilter]); + + const setTimeRangeMemoized: React.Dispatch> = useCallback( + (nextOrCallback) => { + const val = + typeof nextOrCallback === 'function' + ? nextOrCallback(timefilter.getTime()) + : nextOrCallback; + + timefilter.setTime(val); + }, + [timefilter] + ); + + const asEpoch = useMemo(() => { + return { + start: new Date(absoluteTimeRange.from).getTime(), + end: new Date(absoluteTimeRange.to).getTime(), + }; + }, [absoluteTimeRange]); + + return { + timeRange, + absoluteTimeRange: asEpoch, + setTimeRange: setTimeRangeMemoized, + }; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_local_storage.ts b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_local_storage.ts new file mode 100644 index 0000000000000..ea9e13163e4b0 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_local_storage.ts @@ -0,0 +1,60 @@ +/* + * 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 { useState, useEffect, useMemo, useCallback } from 'react'; + +export function useLocalStorage(key: string, defaultValue: T) { + // This is necessary to fix a race condition issue. + // It guarantees that the latest value will be always returned after the value is updated + const [storageUpdate, setStorageUpdate] = useState(0); + + const item = useMemo(() => { + return getFromStorage(key, defaultValue); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [key, storageUpdate, defaultValue]); + + const saveToStorage = useCallback( + (value: T) => { + if (value === undefined) { + window.localStorage.removeItem(key); + } else { + window.localStorage.setItem(key, JSON.stringify(value)); + setStorageUpdate(storageUpdate + 1); + } + }, + [key, storageUpdate] + ); + + useEffect(() => { + function onUpdate(event: StorageEvent) { + if (event.key === key) { + setStorageUpdate(storageUpdate + 1); + } + } + window.addEventListener('storage', onUpdate); + return () => { + window.removeEventListener('storage', onUpdate); + }; + }, [key, setStorageUpdate, storageUpdate]); + + return useMemo(() => [item, saveToStorage] as const, [item, saveToStorage]); +} + +function getFromStorage(keyName: string, defaultValue: T) { + const storedItem = window.localStorage.getItem(keyName); + + if (storedItem !== null) { + try { + return JSON.parse(storedItem) as T; + } catch (err) { + window.localStorage.removeItem(keyName); + // eslint-disable-next-line no-console + console.log(`Unable to decode: ${keyName}`); + } + } + return defaultValue; +} diff --git a/x-pack/packages/observability/observability_utils/hooks/use_theme.ts b/x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_theme.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/hooks/use_theme.ts rename to x-pack/packages/observability/observability_utils/observability_utils_browser/hooks/use_theme.ts diff --git a/x-pack/packages/observability/observability_utils/observability_utils_browser/jest.config.js b/x-pack/packages/observability/observability_utils/observability_utils_browser/jest.config.js new file mode 100644 index 0000000000000..33358c221fa1f --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/jest.config.js @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: [ + '/x-pack/packages/observability/observability_utils/observability_utils_browser', + ], +}; diff --git a/x-pack/packages/observability/observability_utils/observability_utils_browser/kibana.jsonc b/x-pack/packages/observability/observability_utils/observability_utils_browser/kibana.jsonc new file mode 100644 index 0000000000000..dbee36828d080 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/observability-utils-browser", + "owner": "@elastic/observability-ui" +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_browser/package.json b/x-pack/packages/observability/observability_utils/observability_utils_browser/package.json new file mode 100644 index 0000000000000..c72c8c0b45eb0 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/observability-utils-browser", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_browser/tsconfig.json b/x-pack/packages/observability/observability_utils/observability_utils_browser/tsconfig.json new file mode 100644 index 0000000000000..9cfa030bd901d --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/data-plugin", + "@kbn/core-ui-settings-browser", + "@kbn/std", + ] +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_browser/utils/ui_settings/get_timezone.ts b/x-pack/packages/observability/observability_utils/observability_utils_browser/utils/ui_settings/get_timezone.ts new file mode 100644 index 0000000000000..3ad5d17aa61bc --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_browser/utils/ui_settings/get_timezone.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { UI_SETTINGS } from '@kbn/data-plugin/public'; +import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; + +export function getTimeZone(uiSettings?: IUiSettingsClient) { + const kibanaTimeZone = uiSettings?.get<'Browser' | string>(UI_SETTINGS.DATEFORMAT_TZ); + if (!kibanaTimeZone || kibanaTimeZone === 'Browser') { + return 'local'; + } + + return kibanaTimeZone; +} diff --git a/x-pack/packages/observability/observability_utils/array/join_by_key.test.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/array/join_by_key.test.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/array/join_by_key.test.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/array/join_by_key.test.ts diff --git a/x-pack/packages/observability/observability_utils/array/join_by_key.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/array/join_by_key.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/array/join_by_key.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/array/join_by_key.ts diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/entities/get_entity_kuery.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/entities/get_entity_kuery.ts new file mode 100644 index 0000000000000..ba68e544379a4 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/entities/get_entity_kuery.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export function getEntityKuery(entity: Record) { + return Object.entries(entity) + .map(([name, value]) => { + return `(${name}:"${value}")`; + }) + .join(' AND '); +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/es/format_value_for_kql.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/es/format_value_for_kql.ts new file mode 100644 index 0000000000000..a0fb5c15fd03e --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/es/format_value_for_kql.ts @@ -0,0 +1,10 @@ +/* + * 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 function formatValueForKql(value: string) { + return `(${value.replaceAll(/((^|[^\\])):/g, '\\:')})`; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/entity_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/entity_query.ts new file mode 100644 index 0000000000000..f2ae0991eecf4 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/entity_query.ts @@ -0,0 +1,24 @@ +/* + * 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 { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; + +export function entityQuery(entity: Record): QueryDslQueryContainer[] { + return [ + { + bool: { + filter: Object.entries(entity).map(([field, value]) => { + return { + term: { + [field]: value, + }, + }; + }), + }, + }, + ]; +} diff --git a/x-pack/packages/observability/observability_utils/es/queries/exclude_frozen_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/exclude_frozen_query.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/es/queries/exclude_frozen_query.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/exclude_frozen_query.ts diff --git a/x-pack/packages/observability/observability_utils/es/queries/exclude_tiers_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/exclude_tiers_query.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/es/queries/exclude_tiers_query.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/exclude_tiers_query.ts diff --git a/x-pack/packages/observability/observability_utils/es/queries/kql_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/kql_query.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/es/queries/kql_query.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/kql_query.ts diff --git a/x-pack/packages/observability/observability_utils/es/queries/range_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/range_query.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/es/queries/range_query.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/range_query.ts diff --git a/x-pack/packages/observability/observability_utils/es/queries/term_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/term_query.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/es/queries/term_query.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/es/queries/term_query.ts diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/format/integer.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/format/integer.ts new file mode 100644 index 0000000000000..7cf202fb8c811 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/format/integer.ts @@ -0,0 +1,11 @@ +/* + * 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 numeral from '@elastic/numeral'; + +export function formatInteger(num: number) { + return numeral(num).format('0a'); +} diff --git a/x-pack/packages/observability/observability_utils/jest.config.js b/x-pack/packages/observability/observability_utils/observability_utils_common/jest.config.js similarity index 84% rename from x-pack/packages/observability/observability_utils/jest.config.js rename to x-pack/packages/observability/observability_utils/observability_utils_common/jest.config.js index c9dff28ed6cec..ee68881a5863b 100644 --- a/x-pack/packages/observability/observability_utils/jest.config.js +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/jest.config.js @@ -7,6 +7,6 @@ module.exports = { preset: '@kbn/test', - rootDir: '../../../..', - roots: ['/x-pack/packages/observability/observability_utils'], + rootDir: '../../../../..', + roots: ['/x-pack/packages/observability/observability_utils/observability_utils_common'], }; diff --git a/x-pack/packages/observability/observability_utils/kibana.jsonc b/x-pack/packages/observability/observability_utils/observability_utils_common/kibana.jsonc similarity index 61% rename from x-pack/packages/observability/observability_utils/kibana.jsonc rename to x-pack/packages/observability/observability_utils/observability_utils_common/kibana.jsonc index 096b2565d533f..eb120052e5b0e 100644 --- a/x-pack/packages/observability/observability_utils/kibana.jsonc +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/kibana.jsonc @@ -1,5 +1,5 @@ { "type": "shared-common", - "id": "@kbn/observability-utils", + "id": "@kbn/observability-utils-common", "owner": "@elastic/observability-ui" } diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/document_analysis.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/document_analysis.ts new file mode 100644 index 0000000000000..be896571ca217 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/document_analysis.ts @@ -0,0 +1,24 @@ +/* + * 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 DocumentAnalysis { + total: number; + sampled: number; + fields: Array<{ + name: string; + types: string[]; + cardinality: number | null; + values: Array; + empty: boolean; + }>; +} + +export interface TruncatedDocumentAnalysis { + fields: string[]; + total: number; + sampled: number; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/highlight_patterns_from_regex.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/highlight_patterns_from_regex.ts new file mode 100644 index 0000000000000..11ab0c52f1795 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/highlight_patterns_from_regex.ts @@ -0,0 +1,51 @@ +/* + * 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. + */ + +function addCapturingGroupsToRegex(regex: string): string { + // Match all parts of the regex that are not special characters + // We treat constant parts as sequences of characters that are not part of regex syntax + return regex.replaceAll(/((?:\.\*\?)|(?:\.\+\?)|(?:\+\?))/g, (...args) => { + return `(${args[1]})`; + }); +} + +export function highlightPatternFromRegex(pattern: string, str: string): string { + // First, add non-capturing groups to the regex around constant parts + const updatedPattern = addCapturingGroupsToRegex(pattern); + + const regex = new RegExp(updatedPattern, 'ds'); + + const matches = str.match(regex) as + | (RegExpMatchArray & { indices: Array<[number, number]> }) + | null; + + const slices: string[] = []; + + matches?.forEach((_, index) => { + if (index === 0) { + return; + } + + const [, prevEnd] = index > 1 ? matches?.indices[index - 1] : [undefined, undefined]; + const [start, end] = matches?.indices[index]; + + const literalSlice = prevEnd !== undefined ? str.slice(prevEnd, start) : undefined; + + if (literalSlice) { + slices.push(`${literalSlice}`); + } + + const slice = str.slice(start, end); + slices.push(slice); + + if (index === matches.length - 1) { + slices.push(str.slice(end)); + } + }); + + return slices.join(''); +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/merge_sample_documents_with_field_caps.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/merge_sample_documents_with_field_caps.ts new file mode 100644 index 0000000000000..58b6024aed046 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/merge_sample_documents_with_field_caps.ts @@ -0,0 +1,78 @@ +/* + * 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 { castArray, sortBy, uniq } from 'lodash'; +import type { DocumentAnalysis } from './document_analysis'; + +export function mergeSampleDocumentsWithFieldCaps({ + total, + samples, + fieldCaps, +}: { + total: number; + samples: Array>; + fieldCaps: Array<{ name: string; esTypes?: string[] }>; +}): DocumentAnalysis { + const nonEmptyFields = new Set(); + const fieldValues = new Map>(); + + for (const document of samples) { + Object.keys(document).forEach((field) => { + if (!nonEmptyFields.has(field)) { + nonEmptyFields.add(field); + } + + const values = castArray(document[field]); + + const currentFieldValues = fieldValues.get(field) ?? []; + + values.forEach((value) => { + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + currentFieldValues.push(value); + } + }); + + fieldValues.set(field, currentFieldValues); + }); + } + + const fields = fieldCaps.flatMap((spec) => { + const values = fieldValues.get(spec.name); + + const countByValues = new Map(); + + values?.forEach((value) => { + const currentCount = countByValues.get(value) ?? 0; + countByValues.set(value, currentCount + 1); + }); + + const sortedValues = sortBy( + Array.from(countByValues.entries()).map(([value, count]) => { + return { + value, + count, + }; + }), + 'count', + 'desc' + ); + + return { + name: spec.name, + types: spec.esTypes ?? [], + empty: !nonEmptyFields.has(spec.name), + cardinality: countByValues.size || null, + values: uniq(sortedValues.flatMap(({ value }) => value)), + }; + }); + + return { + total, + sampled: samples.length, + fields, + }; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/sort_and_truncate_analyzed_fields.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/sort_and_truncate_analyzed_fields.ts new file mode 100644 index 0000000000000..c9a3e6a156601 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/log_analysis/sort_and_truncate_analyzed_fields.ts @@ -0,0 +1,52 @@ +/* + * 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 { partition, shuffle } from 'lodash'; +import { truncateList } from '@kbn/inference-common'; +import type { DocumentAnalysis, TruncatedDocumentAnalysis } from './document_analysis'; + +export function sortAndTruncateAnalyzedFields( + analysis: DocumentAnalysis +): TruncatedDocumentAnalysis { + const { fields, ...meta } = analysis; + const [nonEmptyFields, emptyFields] = partition(analysis.fields, (field) => !field.empty); + + const sortedFields = [...shuffle(nonEmptyFields), ...shuffle(emptyFields)]; + + return { + ...meta, + fields: truncateList( + sortedFields.map((field) => { + let label = `${field.name}:${field.types.join(',')}`; + + if (field.empty) { + return `${name} (empty)`; + } + + label += ` - ${field.cardinality} distinct values`; + + if (field.name === '@timestamp' || field.name === 'event.ingested') { + return `${label}`; + } + + const shortValues = field.values.filter((value) => { + return String(value).length <= 1024; + }); + + if (shortValues.length) { + return `${label} (${truncateList( + shortValues.map((value) => '`' + value + '`'), + field.types.includes('text') || field.types.includes('match_only_text') ? 2 : 10 + ).join(', ')})`; + } + + return label; + }), + 500 + ).sort(), + }; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/llm/short_id_table.test.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/short_id_table.test.ts new file mode 100644 index 0000000000000..784cf67530652 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/short_id_table.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { ShortIdTable } from './short_id_table'; + +describe('shortIdTable', () => { + it('generates at least 10k unique ids consistently', () => { + const ids = new Set(); + + const table = new ShortIdTable(); + + let i = 10_000; + while (i--) { + const id = table.take(String(i)); + ids.add(id); + } + + expect(ids.size).toBe(10_000); + }); + + it('returns the original id based on the generated id', () => { + const table = new ShortIdTable(); + + const idsByOriginal = new Map(); + + let i = 100; + while (i--) { + const id = table.take(String(i)); + idsByOriginal.set(String(i), id); + } + + expect(idsByOriginal.size).toBe(100); + + expect(() => { + Array.from(idsByOriginal.entries()).forEach(([originalId, shortId]) => { + const returnedOriginalId = table.lookup(shortId); + if (returnedOriginalId !== originalId) { + throw Error( + `Expected shortId ${shortId} to return ${originalId}, but ${returnedOriginalId} was returned instead` + ); + } + }); + }).not.toThrow(); + }); +}); diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/llm/short_id_table.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/short_id_table.ts new file mode 100644 index 0000000000000..30049452ddf51 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/llm/short_id_table.ts @@ -0,0 +1,56 @@ +/* + * 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. + */ + +const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'; + +function generateShortId(size: number): string { + let id = ''; + let i = size; + while (i--) { + const index = Math.floor(Math.random() * ALPHABET.length); + id += ALPHABET[index]; + } + return id; +} + +const MAX_ATTEMPTS_AT_LENGTH = 100; + +export class ShortIdTable { + private byShortId: Map = new Map(); + private byOriginalId: Map = new Map(); + + constructor() {} + + take(originalId: string) { + if (this.byOriginalId.has(originalId)) { + return this.byOriginalId.get(originalId)!; + } + + let uniqueId: string | undefined; + let attemptsAtLength = 0; + let length = 4; + while (!uniqueId) { + const nextId = generateShortId(length); + attemptsAtLength++; + if (!this.byShortId.has(nextId)) { + uniqueId = nextId; + } else if (attemptsAtLength >= MAX_ATTEMPTS_AT_LENGTH) { + attemptsAtLength = 0; + length++; + } + } + + this.byShortId.set(uniqueId, originalId); + this.byOriginalId.set(originalId, uniqueId); + + return uniqueId; + } + + lookup(shortId: string) { + return this.byShortId.get(shortId); + } +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/ml/p_value_to_label.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/ml/p_value_to_label.ts new file mode 100644 index 0000000000000..3f6e0836d129b --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/ml/p_value_to_label.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. + */ + +export const P_VALUE_SIGNIFICANCE_HIGH = 1e-6; +export const P_VALUE_SIGNIFICANCE_MEDIUM = 0.001; + +export function pValueToLabel(pValue: number): 'high' | 'medium' | 'low' { + if (pValue <= P_VALUE_SIGNIFICANCE_HIGH) { + return 'high'; + } else if (pValue <= P_VALUE_SIGNIFICANCE_MEDIUM) { + return 'medium'; + } else { + return 'low'; + } +} diff --git a/x-pack/packages/observability/observability_utils/object/flatten_object.test.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/object/flatten_object.test.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/object/flatten_object.test.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/object/flatten_object.test.ts diff --git a/x-pack/packages/observability/observability_utils/object/flatten_object.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/object/flatten_object.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/object/flatten_object.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/object/flatten_object.ts diff --git a/x-pack/packages/observability/observability_utils/object/merge_plain_object.test.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/object/merge_plain_object.test.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/object/merge_plain_object.test.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/object/merge_plain_object.test.ts diff --git a/x-pack/packages/observability/observability_utils/object/merge_plain_objects.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/object/merge_plain_objects.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/object/merge_plain_objects.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/object/merge_plain_objects.ts diff --git a/x-pack/packages/observability/observability_utils/object/unflatten_object.test.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.test.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/object/unflatten_object.test.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.test.ts diff --git a/x-pack/packages/observability/observability_utils/object/unflatten_object.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.ts similarity index 99% rename from x-pack/packages/observability/observability_utils/object/unflatten_object.ts rename to x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.ts index 142ea2eea6461..83508d5d2dbf5 100644 --- a/x-pack/packages/observability/observability_utils/object/unflatten_object.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.ts @@ -11,7 +11,6 @@ export function unflattenObject(source: Record, target: Record { if (item && typeof item === 'object' && !Array.isArray(item)) { diff --git a/x-pack/packages/observability/observability_utils/package.json b/x-pack/packages/observability/observability_utils/observability_utils_common/package.json similarity index 62% rename from x-pack/packages/observability/observability_utils/package.json rename to x-pack/packages/observability/observability_utils/observability_utils_common/package.json index 06f6e37858927..2f9be5f105279 100644 --- a/x-pack/packages/observability/observability_utils/package.json +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/package.json @@ -1,6 +1,6 @@ { - "name": "@kbn/observability-utils", + "name": "@kbn/observability-utils-common", "private": true, "version": "1.0.0", "license": "Elastic License 2.0" -} \ No newline at end of file +} diff --git a/x-pack/packages/observability/observability_utils/tsconfig.json b/x-pack/packages/observability/observability_utils/observability_utils_common/tsconfig.json similarity index 70% rename from x-pack/packages/observability/observability_utils/tsconfig.json rename to x-pack/packages/observability/observability_utils/observability_utils_common/tsconfig.json index b3f1a4a21c4e7..7954cdc946e9c 100644 --- a/x-pack/packages/observability/observability_utils/tsconfig.json +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../../tsconfig.base.json", + "extends": "../../../../../tsconfig.base.json", "compilerOptions": { "outDir": "target/types", "types": [ @@ -16,11 +16,8 @@ "target/**/*" ], "kbn_references": [ - "@kbn/std", - "@kbn/core", - "@kbn/es-types", - "@kbn/apm-utils", "@kbn/es-query", "@kbn/safer-lodash-set", + "@kbn/inference-common", ] } diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/entities/analyze_documents.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/analyze_documents.ts new file mode 100644 index 0000000000000..0cc1374d8b1d8 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/analyze_documents.ts @@ -0,0 +1,84 @@ +/* + * 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 { mapValues } from 'lodash'; +import { mergeSampleDocumentsWithFieldCaps } from '@kbn/observability-utils-common/llm/log_analysis/merge_sample_documents_with_field_caps'; +import { DocumentAnalysis } from '@kbn/observability-utils-common/llm/log_analysis/document_analysis'; +import type { ObservabilityElasticsearchClient } from '../es/client/create_observability_es_client'; +import { kqlQuery } from '../es/queries/kql_query'; +import { rangeQuery } from '../es/queries/range_query'; + +export async function analyzeDocuments({ + esClient, + kuery, + start, + end, + index, +}: { + esClient: ObservabilityElasticsearchClient; + kuery: string; + start: number; + end: number; + index: string | string[]; +}): Promise { + const [fieldCaps, hits] = await Promise.all([ + esClient.fieldCaps('get_field_caps_for_document_analysis', { + index, + fields: '*', + index_filter: { + bool: { + filter: rangeQuery(start, end), + }, + }, + }), + esClient + .search('get_document_samples', { + index, + size: 1000, + track_total_hits: true, + query: { + bool: { + must: [...kqlQuery(kuery), ...rangeQuery(start, end)], + should: [ + { + function_score: { + functions: [ + { + random_score: {}, + }, + ], + }, + }, + ], + }, + }, + sort: { + _score: { + order: 'desc', + }, + }, + _source: false, + fields: ['*' as const], + }) + .then((response) => ({ + hits: response.hits.hits.map((hit) => + mapValues(hit.fields!, (value) => (value.length === 1 ? value[0] : value)) + ), + total: response.hits.total, + })), + ]); + + const analysis = mergeSampleDocumentsWithFieldCaps({ + samples: hits.hits, + total: hits.total.value, + fieldCaps: Object.entries(fieldCaps.fields).map(([name, specs]) => { + return { name, esTypes: Object.keys(specs) }; + }), + }); + + return analysis; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/entities/get_data_streams_for_entity.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/get_data_streams_for_entity.ts new file mode 100644 index 0000000000000..43d9134c7aaf3 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/get_data_streams_for_entity.ts @@ -0,0 +1,63 @@ +/* + * 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 { compact, uniq } from 'lodash'; +import { ObservabilityElasticsearchClient } from '../es/client/create_observability_es_client'; +import { excludeFrozenQuery } from '../es/queries/exclude_frozen_query'; +import { kqlQuery } from '../es/queries/kql_query'; + +export async function getDataStreamsForEntity({ + esClient, + kuery, + index, +}: { + esClient: ObservabilityElasticsearchClient; + kuery: string; + index: string | string[]; +}) { + const response = await esClient.search('get_data_streams_for_entity', { + track_total_hits: false, + index, + size: 0, + terminate_after: 1, + timeout: '1ms', + aggs: { + indices: { + terms: { + field: '_index', + size: 10000, + }, + }, + }, + query: { + bool: { + filter: [...excludeFrozenQuery(), ...kqlQuery(kuery)], + }, + }, + }); + + const allIndices = + response.aggregations?.indices.buckets.map((bucket) => bucket.key as string) ?? []; + + if (!allIndices.length) { + return { + dataStreams: [], + }; + } + + const resolveIndexResponse = await esClient.client.indices.resolveIndex({ + name: allIndices, + }); + + const dataStreams = uniq( + compact(await resolveIndexResponse.indices.flatMap((idx) => idx.data_stream)) + ); + + return { + dataStreams, + }; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_alerts_for_entity.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_alerts_for_entity.ts new file mode 100644 index 0000000000000..400aad8e94357 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_alerts_for_entity.ts @@ -0,0 +1,57 @@ +/* + * 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 { RulesClient } from '@kbn/alerting-plugin/server'; +import { AlertsClient } from '@kbn/rule-registry-plugin/server'; +import { + ALERT_GROUP_FIELD, + ALERT_GROUP_VALUE, + ALERT_STATUS, + ALERT_STATUS_ACTIVE, + ALERT_TIME_RANGE, +} from '@kbn/rule-data-utils'; +import { kqlQuery } from '../../es/queries/kql_query'; +import { rangeQuery } from '../../es/queries/range_query'; + +export async function getAlertsForEntity({ + start, + end, + entity, + alertsClient, + rulesClient, + size, +}: { + start: number; + end: number; + entity: Record; + alertsClient: AlertsClient; + rulesClient: RulesClient; + size: number; +}) { + const alertsKuery = Object.entries(entity) + .map(([field, value]) => { + return `(${[ + `(${ALERT_GROUP_FIELD}:"${field}" AND ${ALERT_GROUP_VALUE}:"${value}")`, + `(${field}:"${value}")`, + ].join(' OR ')})`; + }) + .join(' AND '); + + const openAlerts = await alertsClient.find({ + size, + query: { + bool: { + filter: [ + ...kqlQuery(alertsKuery), + ...rangeQuery(start, end, ALERT_TIME_RANGE), + { term: { [ALERT_STATUS]: ALERT_STATUS_ACTIVE } }, + ], + }, + }, + }); + + return openAlerts; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_anomalies_for_entity.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_anomalies_for_entity.ts new file mode 100644 index 0000000000000..b8802ed3c9045 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_anomalies_for_entity.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export function getAnomaliesForEntity({ + start, + end, + entity, +}: { + start: number; + end: number; + entity: Record; +}) {} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_slos_for_entity.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_slos_for_entity.ts new file mode 100644 index 0000000000000..fc3a9d7b26d5c --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/entities/signals/get_slos_for_entity.ts @@ -0,0 +1,80 @@ +/* + * 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 { ObservabilityElasticsearchClient } from '../../es/client/create_observability_es_client'; +import { kqlQuery } from '../../es/queries/kql_query'; + +export async function getSlosForEntity({ + start, + end, + entity, + esClient, + sloSummaryIndices, + size, + spaceId, +}: { + start: number; + end: number; + entity: Record; + esClient: ObservabilityElasticsearchClient; + sloSummaryIndices: string | string[]; + size: number; + spaceId: string; +}) { + const slosKuery = Object.entries(entity) + .map(([field, value]) => { + return `(slo.groupings.${field}:"${value}")`; + }) + .join(' AND '); + + const sloSummaryResponse = await esClient.search('get_slo_summaries_for_entity', { + index: sloSummaryIndices, + size, + track_total_hits: false, + query: { + bool: { + filter: [ + ...kqlQuery(slosKuery), + { + range: { + 'slo.createdAt': { + lte: end, + }, + }, + }, + { + range: { + summaryUpdatedAt: { + gte: start, + }, + }, + }, + { + term: { + spaceId, + }, + }, + ], + }, + }, + }); + + return { + ...sloSummaryResponse, + hits: { + ...sloSummaryResponse.hits, + hits: sloSummaryResponse.hits.hits.map((hit) => { + return { + ...hit, + _source: hit._source as Record & { + status: 'VIOLATED' | 'DEGRADED' | 'HEALTHY' | 'NO_DATA'; + }, + }; + }), + }, + }; +} diff --git a/x-pack/packages/observability/observability_utils/es/client/create_observability_es_client.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/client/create_observability_es_client.ts similarity index 61% rename from x-pack/packages/observability/observability_utils/es/client/create_observability_es_client.ts rename to x-pack/packages/observability/observability_utils/observability_utils_server/es/client/create_observability_es_client.ts index 09013dcd5a506..78ed20a582bc3 100644 --- a/x-pack/packages/observability/observability_utils/es/client/create_observability_es_client.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/client/create_observability_es_client.ts @@ -5,11 +5,18 @@ * 2.0. */ +import type { + EsqlQueryRequest, + FieldCapsRequest, + FieldCapsResponse, + MsearchRequest, + SearchResponse, +} from '@elastic/elasticsearch/lib/api/types'; +import { withSpan } from '@kbn/apm-utils'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { ESQLSearchResponse, ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; -import { withSpan } from '@kbn/apm-utils'; -import type { EsqlQueryRequest } from '@elastic/elasticsearch/lib/api/types'; -import { esqlResultToPlainObjects } from '../utils/esql_result_to_plain_objects'; +import { Required } from 'utility-types'; +import { esqlResultToPlainObjects } from '../esql_result_to_plain_objects'; type SearchRequest = ESSearchRequest & { index: string | string[]; @@ -39,7 +46,17 @@ export interface ObservabilityElasticsearchClient { search( operationName: string, parameters: TSearchRequest - ): Promise>; + ): Promise>; + msearch( + operationName: string, + parameters: MsearchRequest + ): Promise<{ + responses: Array>; + }>; + fieldCaps( + operationName: string, + request: Required + ): Promise; esql( operationName: string, parameters: TQueryParams @@ -60,8 +77,38 @@ export function createObservabilityEsClient({ logger: Logger; plugin: string; }): ObservabilityElasticsearchClient { + // wraps the ES calls in a named APM span for better analysis + // (otherwise it would just eg be a _search span) + const callWithLogger = ( + operationName: string, + request: Record, + callback: () => Promise + ) => { + logger.debug(() => `Request (${operationName}):\n${JSON.stringify(request)}`); + return withSpan( + { + name: operationName, + labels: { + plugin, + }, + }, + callback, + logger + ).then((response) => { + logger.trace(() => `Response (${operationName}):\n${JSON.stringify(response, null, 2)}`); + return response; + }); + }; + return { client, + fieldCaps(operationName, parameters) { + return callWithLogger(operationName, parameters, () => { + return client.fieldCaps({ + ...parameters, + }); + }); + }, esql( operationName: string, { parseOutput = true, format = 'json', columnar = false, ...parameters }: TSearchRequest @@ -93,24 +140,17 @@ export function createObservabilityEsClient({ operationName: string, parameters: SearchRequest ) { - logger.trace(() => `Request (${operationName}):\n${JSON.stringify(parameters, null, 2)}`); - // wraps the search operation in a named APM span for better analysis - // (otherwise it would just be a _search span) - return withSpan( - { - name: operationName, - labels: { - plugin, - }, - }, - () => { - return client.search(parameters) as unknown as Promise< - InferSearchResponseOf - >; - } - ).then((response) => { - logger.trace(() => `Response (${operationName}):\n${JSON.stringify(response, null, 2)}`); - return response; + return callWithLogger(operationName, parameters, () => { + return client.search(parameters) as unknown as Promise< + InferSearchResponseOf + >; + }); + }, + msearch(operationName: string, parameters: MsearchRequest) { + return callWithLogger(operationName, parameters, () => { + return client.msearch(parameters) as unknown as Promise<{ + responses: Array>; + }>; }); }, }; diff --git a/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.test.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.test.ts similarity index 100% rename from x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.test.ts rename to x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.test.ts diff --git a/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.ts similarity index 90% rename from x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts rename to x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.ts index 717983a2958c5..34781153532c5 100644 --- a/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.ts @@ -6,7 +6,7 @@ */ import type { ESQLSearchResponse } from '@kbn/es-types'; -import { unflattenObject } from '../../object/unflatten_object'; +import { unflattenObject } from '@kbn/observability-utils-common/object/unflatten_object'; export function esqlResultToPlainObjects( result: ESQLSearchResponse diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/exclude_frozen_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/exclude_frozen_query.ts new file mode 100644 index 0000000000000..f348d925c41ca --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/exclude_frozen_query.ts @@ -0,0 +1,23 @@ +/* + * 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 { estypes } from '@elastic/elasticsearch'; + +export function excludeFrozenQuery(): estypes.QueryDslQueryContainer[] { + return [ + { + bool: { + must_not: [ + { + term: { + _tier: 'data_frozen', + }, + }, + ], + }, + }, + ]; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/kql_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/kql_query.ts new file mode 100644 index 0000000000000..2f560157cc8c6 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/kql_query.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { estypes } from '@elastic/elasticsearch'; +import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; + +export function kqlQuery(kql?: string): estypes.QueryDslQueryContainer[] { + if (!kql) { + return []; + } + + const ast = fromKueryExpression(kql); + return [toElasticsearchQuery(ast)]; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/range_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/range_query.ts new file mode 100644 index 0000000000000..d73476354c377 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/range_query.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 type { estypes } from '@elastic/elasticsearch'; + +export function rangeQuery( + start?: number, + end?: number, + field = '@timestamp' +): estypes.QueryDslQueryContainer[] { + return [ + { + range: { + [field]: { + gte: start, + lte: end, + format: 'epoch_millis', + }, + }, + }, + ]; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/term_query.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/term_query.ts new file mode 100644 index 0000000000000..dfaeb737bf8b7 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/queries/term_query.ts @@ -0,0 +1,24 @@ +/* + * 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 { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; + +interface TermQueryOpts { + queryEmptyString: boolean; +} + +export function termQuery( + field: T, + value: string | boolean | number | undefined | null, + opts: TermQueryOpts = { queryEmptyString: true } +): QueryDslQueryContainer[] { + if (value === null || value === undefined || (!opts.queryEmptyString && value === '')) { + return []; + } + + return [{ term: { [field]: value } }]; +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/jest.config.js b/x-pack/packages/observability/observability_utils/observability_utils_server/jest.config.js new file mode 100644 index 0000000000000..5a52de35fcd06 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/packages/observability/observability_utils/observability_utils_server'], +}; diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/kibana.jsonc b/x-pack/packages/observability/observability_utils/observability_utils_server/kibana.jsonc new file mode 100644 index 0000000000000..4c2f20ef1491f --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-server", + "id": "@kbn/observability-utils-server", + "owner": "@elastic/observability-ui" +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/package.json b/x-pack/packages/observability/observability_utils/observability_utils_server/package.json new file mode 100644 index 0000000000000..43abbbb757fea --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/observability-utils-server", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/tsconfig.json b/x-pack/packages/observability/observability_utils/observability_utils_server/tsconfig.json new file mode 100644 index 0000000000000..f51d93089c627 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/core", + "@kbn/es-types", + "@kbn/apm-utils", + "@kbn/es-query", + "@kbn/observability-utils-common", + "@kbn/alerting-plugin", + "@kbn/rule-registry-plugin", + "@kbn/rule-data-utils", + ] +} diff --git a/x-pack/plugins/data_usage/server/services/autoops_api.ts b/x-pack/plugins/data_usage/server/services/autoops_api.ts index 6a9de27f996f1..03b56df08e9b5 100644 --- a/x-pack/plugins/data_usage/server/services/autoops_api.ts +++ b/x-pack/plugins/data_usage/server/services/autoops_api.ts @@ -63,7 +63,6 @@ export class AutoOpsAPIService { rejectUnauthorized: tlsConfig.rejectUnauthorized, cert: tlsConfig.certificate, key: tlsConfig.key, - ca: tlsConfig.certificateAuthorities, }), }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.test.ts b/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.test.ts index 9e0b06f8482c7..676df7cdf09f5 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.test.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.test.ts @@ -22,7 +22,7 @@ describe('getExceptionListFilter', () => { savedObjectTypes: ['exception-list-agnostic'], }); expect(filter).toEqual( - '(exception-list-agnostic.attributes.list_type: list) AND exception-list-agnostic.attributes.name: "Sample Endpoint Exception List"' + '(exception-list-agnostic.attributes.list_type: list) AND (exception-list-agnostic.attributes.name: "Sample Endpoint Exception List")' ); }); @@ -40,7 +40,7 @@ describe('getExceptionListFilter', () => { savedObjectTypes: ['exception-list'], }); expect(filter).toEqual( - '(exception-list.attributes.list_type: list) AND exception-list.attributes.name: "Sample Endpoint Exception List"' + '(exception-list.attributes.list_type: list) AND (exception-list.attributes.name: "Sample Endpoint Exception List")' ); }); @@ -56,11 +56,12 @@ describe('getExceptionListFilter', () => { test('it should create a filter that searches for both agnostic and single lists with additional filters if searching for both single and agnostic lists', () => { const filter = getExceptionListFilter({ - filter: 'exception-list-agnostic.attributes.name: "Sample Endpoint Exception List"', + filter: + 'exception-list-agnostic.attributes.name: "Sample Endpoint Exception List" OR exception-list.attributes.name: "Sample Rule Exception List"', savedObjectTypes: ['exception-list-agnostic', 'exception-list'], }); expect(filter).toEqual( - '(exception-list-agnostic.attributes.list_type: list OR exception-list.attributes.list_type: list) AND exception-list-agnostic.attributes.name: "Sample Endpoint Exception List"' + '(exception-list-agnostic.attributes.list_type: list OR exception-list.attributes.list_type: list) AND (exception-list-agnostic.attributes.name: "Sample Endpoint Exception List" OR exception-list.attributes.name: "Sample Rule Exception List")' ); }); }); diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.ts b/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.ts index 44a9be320755f..8aedaa13bcab7 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.ts @@ -20,6 +20,6 @@ export const getExceptionListFilter = ({ .join(' OR '); if (filter != null) { - return `(${listTypesFilter}) AND ${filter}`; + return `(${listTypesFilter}) AND (${filter})`; } else return `(${listTypesFilter})`; }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.test.ts b/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.test.ts index 5ffe0967ef330..83623a581d97f 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.test.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.test.ts @@ -60,7 +60,7 @@ describe('find_all_exception_list_item_types', () => { expect(findExceptionList).toHaveBeenCalledWith({ filter: 'exception-list-agnostic.attributes.list_id:(1)', - namespaceType: ['agnostic'], + namespaceType: ['single', 'agnostic'], page: undefined, perPage: 1000, savedObjectsClient, @@ -74,7 +74,7 @@ describe('find_all_exception_list_item_types', () => { expect(findExceptionList).toHaveBeenCalledWith({ filter: 'exception-list.attributes.list_id:(1)', - namespaceType: ['single'], + namespaceType: ['single', 'agnostic'], page: undefined, perPage: 1000, savedObjectsClient, diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.ts b/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.ts index 870acc6cc4462..93c5491a84ddb 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.ts @@ -52,57 +52,40 @@ export const findAllListTypes = async ( nonAgnosticListItems: ExceptionListQueryInfo[], savedObjectsClient: SavedObjectsClientContract ): Promise => { - // Agnostic filter - const agnosticFilter = getListFilter({ - namespaceType: 'agnostic', - objects: agnosticListItems, - }); - - // Non-agnostic filter - const nonAgnosticFilter = getListFilter({ - namespaceType: 'single', - objects: nonAgnosticListItems, - }); - if (!agnosticListItems.length && !nonAgnosticListItems.length) { return null; - } else if (agnosticListItems.length && !nonAgnosticListItems.length) { - return findExceptionList({ - filter: agnosticFilter, - namespaceType: ['agnostic'], - page: undefined, - perPage: CHUNK_PARSED_OBJECT_SIZE, - pit: undefined, - savedObjectsClient, - searchAfter: undefined, - sortField: undefined, - sortOrder: undefined, - }); - } else if (!agnosticListItems.length && nonAgnosticListItems.length) { - return findExceptionList({ - filter: nonAgnosticFilter, - namespaceType: ['single'], - page: undefined, - perPage: CHUNK_PARSED_OBJECT_SIZE, - pit: undefined, - savedObjectsClient, - searchAfter: undefined, - sortField: undefined, - sortOrder: undefined, - }); - } else { - return findExceptionList({ - filter: `${agnosticFilter} OR ${nonAgnosticFilter}`, - namespaceType: ['single', 'agnostic'], - page: undefined, - perPage: CHUNK_PARSED_OBJECT_SIZE, - pit: undefined, - savedObjectsClient, - searchAfter: undefined, - sortField: undefined, - sortOrder: undefined, - }); } + + const filters: string[] = []; + if (agnosticListItems.length > 0) { + filters.push( + getListFilter({ + namespaceType: 'agnostic', + objects: agnosticListItems, + }) + ); + } + + if (nonAgnosticListItems.length > 0) { + filters.push( + getListFilter({ + namespaceType: 'single', + objects: nonAgnosticListItems, + }) + ); + } + + return findExceptionList({ + filter: filters.join(' OR '), + namespaceType: ['single', 'agnostic'], + page: undefined, + perPage: CHUNK_PARSED_OBJECT_SIZE, + pit: undefined, + savedObjectsClient, + searchAfter: undefined, + sortField: undefined, + sortOrder: undefined, + }); }; /** diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts index 753e6476be1ed..da9a08339a45c 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts @@ -28,7 +28,7 @@ const policyFormFields = [ }, ]; -describe.skip('when navigating to integration page', () => { +describe('when navigating to integration page', () => { beforeEach(() => { const integrationsPath = '/app/integrations/browse'; diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/tutorial/tutorial.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/tutorial/tutorial.cy.ts new file mode 100644 index 0000000000000..9aa71604e6a80 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/tutorial/tutorial.cy.ts @@ -0,0 +1,37 @@ +/* + * 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. + */ + +describe('APM tutorial', () => { + beforeEach(() => { + cy.loginAsViewerUser(); + cy.visitKibana('/app/home#/tutorial/apm'); + }); + + it('includes section for APM Server', () => { + cy.contains('APM Server'); + cy.contains('Linux DEB'); + cy.contains('Linux RPM'); + cy.contains('Other Linux'); + cy.contains('macOS'); + cy.contains('Windows'); + cy.contains('Fleet'); + }); + + it('includes section for APM Agents', () => { + cy.contains('APM agents'); + cy.contains('Java'); + cy.contains('RUM'); + cy.contains('Node.js'); + cy.contains('Django'); + cy.contains('Flask'); + cy.contains('Ruby on Rails'); + cy.contains('Rack'); + cy.contains('Go'); + cy.contains('.NET'); + cy.contains('PHP'); + }); +}); 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 cf376e7c78294..9f04bb9a750f3 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 @@ -23,7 +23,7 @@ import { ValuesType } from 'utility-types'; import type { APMError, Metric, Span, Transaction, Event } from '@kbn/apm-types/es_schemas_ui'; import type { InspectResponse } from '@kbn/observability-plugin/typings/common'; import type { DataTier } from '@kbn/observability-shared-plugin/common'; -import { excludeTiersQuery } from '@kbn/observability-utils/es/queries/exclude_tiers_query'; +import { excludeTiersQuery } from '@kbn/observability-utils-common/es/queries/exclude_tiers_query'; import { withApmSpan } from '../../../../utils'; import type { ApmDataSource } from '../../../../../common/data_source'; import { cancelEsRequestOnAbort } from '../cancel_es_request_on_abort'; 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 cad0b03579e3d..c1f8d5e3fce1f 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 @@ -6,7 +6,7 @@ */ import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { DataTier } from '@kbn/observability-shared-plugin/common'; -import { excludeTiersQuery } from '@kbn/observability-utils/es/queries/exclude_tiers_query'; +import { excludeTiersQuery } from '@kbn/observability-utils-common/es/queries/exclude_tiers_query'; export function getDataTierFilterCombined({ filter, diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/utils/unflatten_known_fields.ts b/x-pack/plugins/observability_solution/apm_data_access/server/utils/unflatten_known_fields.ts index b9a4322269828..6c9fe4c39b001 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/utils/unflatten_known_fields.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/utils/unflatten_known_fields.ts @@ -8,8 +8,8 @@ import type { DedotObject } from '@kbn/utility-types'; import * as APM_EVENT_FIELDS_MAP from '@kbn/apm-types/es_fields'; import type { ValuesType } from 'utility-types'; -import { unflattenObject } from '@kbn/observability-utils/object/unflatten_object'; -import { mergePlainObjects } from '@kbn/observability-utils/object/merge_plain_objects'; +import { unflattenObject } from '@kbn/observability-utils-common/object/unflatten_object'; +import { mergePlainObjects } from '@kbn/observability-utils-common/object/merge_plain_objects'; import { castArray, isArray } from 'lodash'; import { AgentName } from '@kbn/elastic-agent-utils'; import { EventOutcome } from '@kbn/apm-types/src/es_schemas/raw/fields'; diff --git a/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json b/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json index aeeb73bee2857..d4c38fddf967e 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json +++ b/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json @@ -20,8 +20,8 @@ "@kbn/apm-utils", "@kbn/core-http-server", "@kbn/security-plugin-types-server", - "@kbn/observability-utils", "@kbn/utility-types", - "@kbn/elastic-agent-utils" + "@kbn/elastic-agent-utils", + "@kbn/observability-utils-common" ] } diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.test.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.test.ts index 19f7e47e84fce..e6bf32332a51f 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.test.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { type EntityClient } from '@kbn/entityManager-plugin/server/lib/entity_client'; import { type InfraMetricsClient } from '../../lib/helpers/get_infra_metrics_client'; import { getDataStreamTypes } from './get_data_stream_types'; diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.ts index f9b2d41bbe050..2d587a6e7d9a9 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.ts @@ -8,7 +8,7 @@ import { type EntityClient } from '@kbn/entityManager-plugin/server/lib/entity_client'; import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common'; import { EntityDataStreamType } from '@kbn/observability-shared-plugin/common'; -import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { castArray } from 'lodash'; import { type InfraMetricsClient } from '../../lib/helpers/get_infra_metrics_client'; import { getHasMetricsData } from './get_has_metrics_data'; diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_latest_entity.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_latest_entity.ts index 31e778313f939..0756bc3d52c8f 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_latest_entity.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_latest_entity.ts @@ -8,7 +8,7 @@ import { ENTITY_LATEST, entitiesAliasPattern } from '@kbn/entities-schema'; import { type EntityClient } from '@kbn/entityManager-plugin/server/lib/entity_client'; import { ENTITY_TYPE, SOURCE_DATA_STREAM_TYPE } from '@kbn/observability-shared-plugin/common'; -import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({ type: '*', diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts index 1a8707678e8f7..30be4fc9da498 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts @@ -8,7 +8,7 @@ import { schema } from '@kbn/config-schema'; import { METRICS_APP_ID } from '@kbn/deeplinks-observability/constants'; import { entityCentricExperience } from '@kbn/observability-plugin/common'; -import { createObservabilityEsClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import { createObservabilityEsClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITY_TYPES } from '@kbn/observability-shared-plugin/common'; import { getInfraMetricsClient } from '../../lib/helpers/get_infra_metrics_client'; import { InfraBackendLibs } from '../../lib/infra_types'; diff --git a/x-pack/plugins/observability_solution/infra/tsconfig.json b/x-pack/plugins/observability_solution/infra/tsconfig.json index 2103350048e4b..efd8be77b688c 100644 --- a/x-pack/plugins/observability_solution/infra/tsconfig.json +++ b/x-pack/plugins/observability_solution/infra/tsconfig.json @@ -114,9 +114,9 @@ "@kbn/management-settings-ids", "@kbn/core-ui-settings-common", "@kbn/entityManager-plugin", - "@kbn/observability-utils", "@kbn/entities-schema", - "@kbn/zod" + "@kbn/zod", + "@kbn/observability-utils-server" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx index 0964b7bb39465..6cfdc079be299 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx @@ -8,7 +8,7 @@ import { EuiSpacer } from '@elastic/eui'; import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import React from 'react'; import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { flattenObject } from '@kbn/observability-utils/object/flatten_object'; +import { flattenObject } from '@kbn/observability-utils-common/object/flatten_object'; import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; import { useKibana } from '../../hooks/use_kibana'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_entity_manager.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_entity_manager.ts index 1082017e1ad7a..740c88eb8a9b0 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_entity_manager.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_entity_manager.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; +import { useAbortableAsync } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; import { useState } from 'react'; import { useKibana } from './use_kibana'; diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_abortable_async.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_abortable_async.ts index 84cef842488e0..1db3b512bbdd6 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_abortable_async.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_abortable_async.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; +import { useAbortableAsync } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; import { i18n } from '@kbn/i18n'; import { IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser'; import { useKibana } from './use_kibana'; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts index bab4af50e316e..87d0c375149e0 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts @@ -6,7 +6,7 @@ */ import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITIES_LATEST_ALIAS, type EntityGroup, diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_types.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_types.ts index 99b8829b600b2..e944e27379ab5 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_types.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import type { EntityInstance } from '@kbn/entities-schema'; import { ENTITIES_LATEST_ALIAS } from '../../../common/entities'; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index 7a65ac5039615..c4bf13c5ec140 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -5,19 +5,19 @@ * 2.0. */ -import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import type { QueryDslQueryContainer, ScalarValue } from '@elastic/elasticsearch/lib/api/types'; +import type { EntityInstance } from '@kbn/entities-schema'; import { + ENTITY_DISPLAY_NAME, ENTITY_LAST_SEEN, ENTITY_TYPE, - ENTITY_DISPLAY_NAME, } from '@kbn/observability-shared-plugin/common'; -import type { QueryDslQueryContainer, ScalarValue } from '@elastic/elasticsearch/lib/api/types'; -import type { EntityInstance } from '@kbn/entities-schema'; +import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITIES_LATEST_ALIAS, + InventoryEntity, MAX_NUMBER_OF_ENTITIES, type EntityColumnIds, - InventoryEntity, } from '../../../common/entities'; import { getBuiltinEntityDefinitionIdESQLWhereClause } from './query_helper'; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts index bdf0b1f59af01..992729a9c1aa0 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts @@ -6,19 +6,19 @@ */ import { INVENTORY_APP_ID } from '@kbn/deeplinks-observability/constants'; import { jsonRt } from '@kbn/io-ts-utils'; -import { createObservabilityEsClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; +import { joinByKey } from '@kbn/observability-utils-common/array/join_by_key'; +import { createObservabilityEsClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import * as t from 'io-ts'; import { orderBy } from 'lodash'; -import { joinByKey } from '@kbn/observability-utils/array/join_by_key'; -import { entityColumnIdsRt, InventoryEntity } from '../../../common/entities'; +import { InventoryEntity, entityColumnIdsRt } from '../../../common/entities'; +import { createAlertsClient } from '../../lib/create_alerts_client.ts/create_alerts_client'; import { createInventoryServerRoute } from '../create_inventory_server_route'; +import { getEntityGroupsBy } from './get_entity_groups'; import { getEntityTypes } from './get_entity_types'; +import { getIdentityFieldsPerEntityType } from './get_identity_fields_per_entity_type'; import { getLatestEntities } from './get_latest_entities'; -import { createAlertsClient } from '../../lib/create_alerts_client.ts/create_alerts_client'; import { getLatestEntitiesAlerts } from './get_latest_entities_alerts'; -import { getIdentityFieldsPerEntityType } from './get_identity_fields_per_entity_type'; -import { getEntityGroupsBy } from './get_entity_groups'; export const getEntityTypesRoute = createInventoryServerRoute({ endpoint: 'GET /internal/inventory/entities/types', diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts b/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts index d328a4f3b8d6f..2f59478f17c02 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts @@ -5,7 +5,7 @@ * 2.0. */ import type { Logger } from '@kbn/core/server'; -import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { getBuiltinEntityDefinitionIdESQLWhereClause } from '../entities/query_helper'; import { ENTITIES_LATEST_ALIAS } from '../../../common/entities'; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/has_data/route.ts b/x-pack/plugins/observability_solution/inventory/server/routes/has_data/route.ts index aae8be7f846f8..f0e582b396177 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/has_data/route.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/has_data/route.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { createObservabilityEsClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import { createObservabilityEsClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { INVENTORY_APP_ID } from '@kbn/deeplinks-observability/constants'; import { createInventoryServerRoute } from '../create_inventory_server_route'; import { getHasData } from './get_has_data'; diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index e9949e60201c8..5094201cc2975 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -20,7 +20,6 @@ "@kbn/server-route-repository", "@kbn/shared-ux-link-redirect-app", "@kbn/typed-react-router-config", - "@kbn/observability-utils", "@kbn/kibana-react-plugin", "@kbn/i18n", "@kbn/deeplinks-observability", @@ -57,6 +56,9 @@ "@kbn/deeplinks-analytics", "@kbn/controls-plugin", "@kbn/securitysolution-io-ts-types", - "@kbn/react-hooks" + "@kbn/react-hooks", + "@kbn/observability-utils-common", + "@kbn/observability-utils-browser", + "@kbn/observability-utils-server" ] } diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx index 29b2a1319feff..77833e80ec199 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx @@ -8,7 +8,7 @@ import { EuiLoadingSpinner, EuiFlexItem } from '@elastic/eui'; import { css } from '@emotion/css'; import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; import type { GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; -import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; +import { useAbortableAsync } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import { v4 } from 'uuid'; import { ErrorMessage } from '../../components/error_message'; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx index 7b88081ca5503..46fe9ea2d9dd2 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx @@ -10,7 +10,7 @@ import type { ESQLSearchResponse } from '@kbn/es-types'; import { i18n } from '@kbn/i18n'; import { type GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; import type { Suggestion } from '@kbn/lens-plugin/public'; -import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; +import { useAbortableAsync } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; import React, { useMemo } from 'react'; import { ErrorMessage } from '../../components/error_message'; import { useKibana } from '../../hooks/use_kibana'; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx index 8d0056dbd538d..469baf6e07f5c 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx @@ -11,7 +11,7 @@ import type { ESQLColumn, ESQLRow } from '@kbn/es-types'; import { GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; import { Item } from '@kbn/investigation-shared'; import type { Suggestion } from '@kbn/lens-plugin/public'; -import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; +import { useAbortableAsync } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; import React, { useEffect, useMemo, useState } from 'react'; import { ErrorMessage } from '../../../../components/error_message'; import { SuggestVisualizationList } from '../../../../components/suggest_visualization_list'; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/events_timeline/events_timeline.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/events_timeline/events_timeline.tsx index befa50bcc0e8d..c3f92139bd936 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/events_timeline/events_timeline.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/events_timeline/events_timeline.tsx @@ -10,7 +10,7 @@ import moment from 'moment'; import { Chart, Axis, AreaSeries, Position, ScaleType, Settings } from '@elastic/charts'; import { useActiveCursor } from '@kbn/charts-plugin/public'; import { EuiSkeletonText } from '@elastic/eui'; -import { getBrushData } from '@kbn/observability-utils/chart/utils'; +import { getBrushData } from '@kbn/observability-utils-browser/chart/utils'; import { Group } from '@kbn/observability-alerting-rule-utils'; import { ALERT_GROUP } from '@kbn/rule-data-utils'; import { SERVICE_NAME } from '@kbn/observability-shared-plugin/common'; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/lib/get_sample_documents.ts b/x-pack/plugins/observability_solution/investigate_app/server/lib/get_sample_documents.ts index 9621a5ff1a4ed..966bda5fc6169 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/lib/get_sample_documents.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/lib/get_sample_documents.ts @@ -7,7 +7,7 @@ import pLimit from 'p-limit'; import { estypes } from '@elastic/elasticsearch'; import { castArray, sortBy, uniq, partition, shuffle } from 'lodash'; -import { truncateList } from '@kbn/inference-plugin/common/utils/truncate_list'; +import { truncateList } from '@kbn/inference-common'; import { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { rangeQuery, excludeFrozenQuery } from './queries'; diff --git a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json index d3974c0c0ed49..0851a13367091 100644 --- a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json +++ b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json @@ -62,13 +62,13 @@ "@kbn/licensing-plugin", "@kbn/rule-data-utils", "@kbn/entities-schema", - "@kbn/inference-plugin", "@kbn/core-elasticsearch-server", "@kbn/calculate-auto", "@kbn/ml-random-sampler-utils", "@kbn/charts-plugin", - "@kbn/observability-utils", "@kbn/observability-alerting-rule-utils", + "@kbn/observability-utils-browser", "@kbn/usage-collection-plugin", + "@kbn/inference-common", ], } diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts index 2b04a99bd4f9c..43ba880b21204 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts @@ -18,7 +18,8 @@ import { import { closeModalIfVisible, closeToastIfVisible } from '../../tasks/integrations'; import { RESULTS_TABLE, RESULTS_TABLE_BUTTON } from '../../screens/live_query'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/181889 +describe.skip( 'Alert Event Details', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'], diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx index 3b1112d47c91d..0a1733bd831fd 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx @@ -69,6 +69,7 @@ import { useRuleForms, useRuleFormsErrors, useRuleIndexPattern } from '../form'; import { useEsqlIndex, useEsqlQueryForAboutStep } from '../../hooks'; import { CustomHeaderPageMemo } from '..'; import { SaveWithErrorsModal } from '../../components/save_with_errors_confirmation'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; import { ALERT_SUPPRESSION_FIELDS_FIELD_NAME } from '../../../rule_creation/components/alert_suppression_edit'; const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { @@ -86,11 +87,14 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { useListsConfig(); const { application, triggersActionsUi } = useKibana().services; const { navigateToApp } = application; + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); const { detailName: ruleId } = useParams<{ detailName: string }>(); const [activeStep, setActiveStep] = useState( - rule.immutable ? RuleStep.ruleActions : RuleStep.defineRule + !isPrebuiltRulesCustomizationEnabled && rule.immutable + ? RuleStep.ruleActions + : RuleStep.defineRule ); const { mutateAsync: updateRule, isLoading } = useUpdateRule(); const [isRulePreviewVisible, setIsRulePreviewVisible] = useState(true); @@ -211,7 +215,7 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { 'data-test-subj': 'edit-rule-define-tab', id: RuleStep.defineRule, name: ruleI18n.DEFINITION, - disabled: rule?.immutable, + disabled: !isPrebuiltRulesCustomizationEnabled && rule?.immutable, content: (
= ({ rule }) => { 'data-test-subj': 'edit-rule-about-tab', id: RuleStep.aboutRule, name: ruleI18n.ABOUT, - disabled: rule?.immutable, + disabled: !isPrebuiltRulesCustomizationEnabled && rule?.immutable, content: (
= ({ rule }) => { 'data-test-subj': 'edit-rule-schedule-tab', id: RuleStep.scheduleRule, name: ruleI18n.SCHEDULE, - disabled: rule?.immutable, + disabled: !isPrebuiltRulesCustomizationEnabled && rule?.immutable, content: (
= ({ rule }) => { }, ], [ + isPrebuiltRulesCustomizationEnabled, rule?.immutable, rule?.id, activeStep, @@ -356,15 +361,15 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { isIndexPatternLoading, isQueryBarValid, defineStepData, + memoizedIndex, aboutStepData, aboutStepForm, + esqlQueryForAboutStep, scheduleStepData, scheduleStepForm, actionsStepData, actionMessageParams, actionsStepForm, - memoizedIndex, - esqlQueryForAboutStep, ] ); @@ -414,7 +419,7 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { setNonBlockingRuleErrors([]); const actionsStepFormValid = await actionsStepForm.validate(); - if (rule.immutable) { + if (!isPrebuiltRulesCustomizationEnabled && rule.immutable) { // Since users cannot edit Define, About and Schedule tabs of the rule, we skip validation of those to avoid // user confusion of seeing that those tabs have error and not being able to see or do anything about that. // We will need to remove this condition once rule customization work is done. @@ -451,11 +456,12 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { showSaveWithErrorsModal(); } }, [ + actionsStepForm, + isPrebuiltRulesCustomizationEnabled, rule.immutable, defineStepForm, aboutStepForm, scheduleStepForm, - actionsStepForm, getRuleFormsErrors, saveChanges, showSaveWithErrorsModal, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx index f3d0930d7c1fe..a4c85391a8063 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx @@ -25,6 +25,7 @@ import { useDownloadExportedRules } from '../../../rule_management/logic/bulk_ac import { useHasActionsPrivileges } from './use_has_actions_privileges'; import type { TimeRange } from '../../../rule_gaps/types'; import { useScheduleRuleRun } from '../../../rule_gaps/logic/use_schedule_rule_run'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; import { ManualRuleRunEventTypes } from '../../../../common/lib/telemetry'; export const useRulesTableActions = ({ @@ -46,6 +47,7 @@ export const useRulesTableActions = ({ const { bulkExport } = useBulkExport(); const downloadExportedRules = useDownloadExportedRules(); const { scheduleRuleRun } = useScheduleRuleRun(); + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); return [ { @@ -116,7 +118,7 @@ export const useRulesTableActions = ({ await downloadExportedRules(response); } }, - enabled: (rule: Rule) => !rule.immutable, + enabled: (rule: Rule) => isPrebuiltRulesCustomizationEnabled || !rule.immutable, }, { type: 'icon', diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx index a786b95979d43..f34fca18ca6e3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx @@ -14,6 +14,7 @@ import { } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../detection_engine/rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; import { useScheduleRuleRun } from '../../../../detection_engine/rule_gaps/logic/use_schedule_rule_run'; import type { TimeRange } from '../../../../detection_engine/rule_gaps/types'; import { APP_UI_ID, SecurityPageName } from '../../../../../common/constants'; @@ -72,6 +73,7 @@ const RuleActionsOverflowComponent = ({ application: { navigateToApp }, telemetry, } = useKibana().services; + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); const { startTransaction } = useStartTransaction(); const { executeBulkAction } = useExecuteBulkAction({ suppressSuccessToast: true }); const { bulkExport } = useBulkExport(); @@ -137,7 +139,10 @@ const RuleActionsOverflowComponent = ({ { startTransaction({ name: SINGLE_RULE_ACTIONS.EXPORT }); @@ -203,21 +208,22 @@ const RuleActionsOverflowComponent = ({ ] : [], [ - bulkExport, + rule, canDuplicateRuleWithActions, + userHasPermissions, + isPrebuiltRulesCustomizationEnabled, + startTransaction, closePopover, + showBulkDuplicateExceptionsConfirmation, executeBulkAction, navigateToApp, - onRuleDeletedCallback, - rule, - showBulkDuplicateExceptionsConfirmation, - showManualRuleRunConfirmation, - startTransaction, - userHasPermissions, + bulkExport, downloadExportedRules, - confirmDeletion, - scheduleRuleRun, + showManualRuleRunConfirmation, telemetry, + scheduleRuleRun, + confirmDeletion, + onRuleDeletedCallback, ] ); diff --git a/x-pack/plugins/security_solution/public/detections/index.ts b/x-pack/plugins/security_solution/public/detections/index.ts index 77d131377f9f5..1f9ce0b6fe012 100644 --- a/x-pack/plugins/security_solution/public/detections/index.ts +++ b/x-pack/plugins/security_solution/public/detections/index.ts @@ -12,6 +12,7 @@ import { getDataTablesInStorageByIds } from '../timelines/containers/local_stora import { routes } from './routes'; import type { SecuritySubPlugin } from '../app/types'; import { runDetectionMigrations } from './migrations'; +import type { StartPlugins } from '../types'; export const DETECTIONS_TABLE_IDS: TableIdLiteral[] = [ TableId.alertsOnRuleDetailsPage, @@ -21,8 +22,8 @@ export const DETECTIONS_TABLE_IDS: TableIdLiteral[] = [ export class Detections { public setup() {} - public start(storage: Storage): SecuritySubPlugin { - runDetectionMigrations(); + public async start(storage: Storage, plugins: StartPlugins): Promise { + await runDetectionMigrations(storage, plugins); return { storageDataTables: { diff --git a/x-pack/plugins/security_solution/public/detections/migrations.ts b/x-pack/plugins/security_solution/public/detections/migrations.ts index 81009f63747a6..324abc443cb04 100644 --- a/x-pack/plugins/security_solution/public/detections/migrations.ts +++ b/x-pack/plugins/security_solution/public/detections/migrations.ts @@ -5,16 +5,21 @@ * 2.0. */ -import { Storage } from '@kbn/kibana-utils-plugin/public'; +import type { Storage } from '@kbn/kibana-utils-plugin/public'; import { migrateAlertPageControlsTo816 } from '../timelines/containers/local_storage/migrate_alert_page_controls'; +import type { StartPlugins } from '../types'; -type LocalStorageMigrator = (storage: Storage) => void; +/* Migrator could be sync or async */ +type LocalStorageMigrator = (storage: Storage, plugins: StartPlugins) => void | Promise; -const runLocalStorageMigration = (fn: LocalStorageMigrator) => { - const storage = new Storage(localStorage); - fn(storage); +const getLocalStorageMigrationRunner = (storage: Storage, plugins: StartPlugins) => { + const runLocalStorageMigration = async (fn: LocalStorageMigrator) => { + await fn(storage, plugins); + }; + return runLocalStorageMigration; }; -export const runDetectionMigrations = () => { - runLocalStorageMigration(migrateAlertPageControlsTo816); +export const runDetectionMigrations = async (storage: Storage, plugins: StartPlugins) => { + const runLocalStorageMigration = getLocalStorageMigrationRunner(storage, plugins); + await runLocalStorageMigration(migrateAlertPageControlsTo816); }; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index 17f1ba842f8cb..b20e645d71c2c 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -256,8 +256,9 @@ export class Plugin implements IPlugin { const subPlugins = await this.createSubPlugins(); + const alerts = await subPlugins.alerts.start(storage, plugins); return { - alerts: subPlugins.alerts.start(storage), + alerts, attackDiscovery: subPlugins.attackDiscovery.start(), cases: subPlugins.cases.start(), cloudDefend: subPlugins.cloudDefend.start(), diff --git a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/migrate_alert_page_contorls.test.ts b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/migrate_alert_page_contorls.test.ts index 575d5bcd6dab3..de0e085fb4ed9 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/migrate_alert_page_contorls.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/migrate_alert_page_contorls.test.ts @@ -7,9 +7,10 @@ import { Storage } from '@kbn/kibana-utils-plugin/public'; import { - PAGE_FILTER_STORAGE_KEY, + GET_PAGE_FILTER_STORAGE_KEY, migrateAlertPageControlsTo816, } from './migrate_alert_page_controls'; +import type { StartPlugins } from '../../../types'; const OLD_FORMAT = { viewMode: 'view', @@ -216,40 +217,94 @@ const NEW_FORMAT = { }; const storage = new Storage(localStorage); +const mockPlugins = { + spaces: { + getActiveSpace: jest.fn().mockResolvedValue({ id: 'default' }), + }, +} as unknown as StartPlugins; + describe('migrateAlertPageControlsTo816', () => { beforeEach(() => { storage.clear(); }); - it('should migrate the old format to the new format', () => { - storage.set(PAGE_FILTER_STORAGE_KEY, OLD_FORMAT); - migrateAlertPageControlsTo816(storage); - const migrated = storage.get(PAGE_FILTER_STORAGE_KEY); - expect(migrated).toMatchObject(NEW_FORMAT); - }); + describe('Default space', () => { + beforeEach(() => { + if (mockPlugins.spaces?.getActiveSpace) { + mockPlugins.spaces.getActiveSpace = jest.fn().mockResolvedValue({ id: 'default' }); + } + }); + it('should migrate the old format to the new format', async () => { + storage.set(GET_PAGE_FILTER_STORAGE_KEY(), OLD_FORMAT); + await migrateAlertPageControlsTo816(storage, mockPlugins); + const migrated = storage.get(GET_PAGE_FILTER_STORAGE_KEY()); + expect(migrated).toMatchObject(NEW_FORMAT); + }); - it('should be a no-op if the new format already exists', () => { - storage.set(PAGE_FILTER_STORAGE_KEY, NEW_FORMAT); - migrateAlertPageControlsTo816(storage); - const migrated = storage.get(PAGE_FILTER_STORAGE_KEY); - expect(migrated).toMatchObject(NEW_FORMAT); - }); + it('should be a no-op if the new format already exists', async () => { + storage.set(GET_PAGE_FILTER_STORAGE_KEY(), NEW_FORMAT); + await migrateAlertPageControlsTo816(storage, mockPlugins); + const migrated = storage.get(GET_PAGE_FILTER_STORAGE_KEY()); + expect(migrated).toMatchObject(NEW_FORMAT); + }); - it('should be a no-op if no value is present in localstorage for page filters ', () => { - migrateAlertPageControlsTo816(storage); - const migrated = storage.get(PAGE_FILTER_STORAGE_KEY); - expect(migrated).toBeNull(); + it('should be a no-op if no value is present in localstorage for page filters ', async () => { + await migrateAlertPageControlsTo816(storage, mockPlugins); + const migrated = storage.get(GET_PAGE_FILTER_STORAGE_KEY()); + expect(migrated).toBeNull(); + }); + + it('should convert custom old format correctly', async () => { + const MODIFIED_OLD_FORMAT = structuredClone(OLD_FORMAT); + MODIFIED_OLD_FORMAT.panels['0'].explicitInput.hideExists = true; + MODIFIED_OLD_FORMAT.chainingSystem = 'NONE'; + storage.set(GET_PAGE_FILTER_STORAGE_KEY(), MODIFIED_OLD_FORMAT); + await migrateAlertPageControlsTo816(storage, mockPlugins); + const migrated = storage.get(GET_PAGE_FILTER_STORAGE_KEY()); + const EXPECTED_NEW_FORMAT = structuredClone(NEW_FORMAT); + EXPECTED_NEW_FORMAT.initialChildControlState['0'].hideExists = true; + EXPECTED_NEW_FORMAT.chainingSystem = 'NONE'; + expect(migrated).toMatchObject(EXPECTED_NEW_FORMAT); + }); }); - it('should convert custom old format correctly', () => { - const MODIFIED_OLD_FORMAT = structuredClone(OLD_FORMAT); - MODIFIED_OLD_FORMAT.panels['0'].explicitInput.hideExists = true; - MODIFIED_OLD_FORMAT.chainingSystem = 'NONE'; - storage.set(PAGE_FILTER_STORAGE_KEY, MODIFIED_OLD_FORMAT); - migrateAlertPageControlsTo816(storage); - const migrated = storage.get(PAGE_FILTER_STORAGE_KEY); - const EXPECTED_NEW_FORMAT = structuredClone(NEW_FORMAT); - EXPECTED_NEW_FORMAT.initialChildControlState['0'].hideExists = true; - EXPECTED_NEW_FORMAT.chainingSystem = 'NONE'; - expect(migrated).toMatchObject(EXPECTED_NEW_FORMAT); + describe('Non Default space', () => { + const nonDefaultSpaceId = 'space1'; + beforeEach(() => { + if (mockPlugins.spaces?.getActiveSpace) { + mockPlugins.spaces.getActiveSpace = jest.fn().mockResolvedValue({ id: nonDefaultSpaceId }); + } + }); + it('should migrate the old format to the new format', async () => { + storage.set(GET_PAGE_FILTER_STORAGE_KEY(nonDefaultSpaceId), OLD_FORMAT); + await migrateAlertPageControlsTo816(storage, mockPlugins); + const migrated = storage.get(GET_PAGE_FILTER_STORAGE_KEY(nonDefaultSpaceId)); + expect(migrated).toMatchObject(NEW_FORMAT); + }); + + it('should be a no-op if the new format already exists', async () => { + storage.set(GET_PAGE_FILTER_STORAGE_KEY(nonDefaultSpaceId), NEW_FORMAT); + await migrateAlertPageControlsTo816(storage, mockPlugins); + const migrated = storage.get(GET_PAGE_FILTER_STORAGE_KEY(nonDefaultSpaceId)); + expect(migrated).toMatchObject(NEW_FORMAT); + }); + + it('should be a no-op if no value is present in localstorage for page filters ', async () => { + await migrateAlertPageControlsTo816(storage, mockPlugins); + const migrated = storage.get(GET_PAGE_FILTER_STORAGE_KEY(nonDefaultSpaceId)); + expect(migrated).toBeNull(); + }); + + it('should convert custom old format correctly', async () => { + const MODIFIED_OLD_FORMAT = structuredClone(OLD_FORMAT); + MODIFIED_OLD_FORMAT.panels['0'].explicitInput.hideExists = true; + MODIFIED_OLD_FORMAT.chainingSystem = 'NONE'; + storage.set(GET_PAGE_FILTER_STORAGE_KEY(nonDefaultSpaceId), MODIFIED_OLD_FORMAT); + await migrateAlertPageControlsTo816(storage, mockPlugins); + const migrated = storage.get(GET_PAGE_FILTER_STORAGE_KEY(nonDefaultSpaceId)); + const EXPECTED_NEW_FORMAT = structuredClone(NEW_FORMAT); + EXPECTED_NEW_FORMAT.initialChildControlState['0'].hideExists = true; + EXPECTED_NEW_FORMAT.chainingSystem = 'NONE'; + expect(migrated).toMatchObject(EXPECTED_NEW_FORMAT); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/migrate_alert_page_controls.ts b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/migrate_alert_page_controls.ts index ac46d42035155..7152ef7738bcc 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/migrate_alert_page_controls.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/migrate_alert_page_controls.ts @@ -7,8 +7,10 @@ import type { DefaultControlState, ControlGroupRuntimeState } from '@kbn/controls-plugin/common'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; +import type { StartPlugins } from '../../../types'; -export const PAGE_FILTER_STORAGE_KEY = 'siem.default.pageFilters'; +export const GET_PAGE_FILTER_STORAGE_KEY = (spaceId: string = 'default') => + `siem.${spaceId}.pageFilters`; interface OldFormat { viewMode: string; @@ -96,8 +98,11 @@ interface NewFormatExplicitInput { * This migration script is to migrate the old format to the new format. * */ -export function migrateAlertPageControlsTo816(storage: Storage) { - const oldFormat: OldFormat = storage.get(PAGE_FILTER_STORAGE_KEY); +export async function migrateAlertPageControlsTo816(storage: Storage, plugins: StartPlugins) { + const space = await plugins.spaces?.getActiveSpace(); + const spaceId = space?.id ?? 'default'; + const storageKey = GET_PAGE_FILTER_STORAGE_KEY(spaceId); + const oldFormat: OldFormat = storage.get(GET_PAGE_FILTER_STORAGE_KEY(spaceId)); if (oldFormat && Object.keys(oldFormat).includes('panels')) { // Only run when it is old format const newFormat: ControlGroupRuntimeState = { @@ -131,6 +136,6 @@ export function migrateAlertPageControlsTo816(storage: Storage) { }; } - storage.set(PAGE_FILTER_STORAGE_KEY, newFormat); + storage.set(storageKey, newFormat); } } diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index 55fce6a46dba8..6642e02d5ecd6 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -248,7 +248,7 @@ export interface SubPlugins { // TODO: find a better way to defined these types export interface StartedSubPlugins { [CASES_SUB_PLUGIN_KEY]: ReturnType; - alerts: ReturnType; + alerts: Awaited>; attackDiscovery: ReturnType; cloudDefend: ReturnType; cloudSecurityPosture: ReturnType; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.mock.ts new file mode 100644 index 0000000000000..b237a9e3c0dcc --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.mock.ts @@ -0,0 +1,64 @@ +/* + * 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. + */ + +/** + * Investigation guide, medium size, version A (original). + */ +export const TEXT_M_A = + '## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n'; + +/** + * Investigation guide, medium size, version B (version A that was modified in one way). + * Modification: last line has been removed. + */ +export const TEXT_M_B = + '## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n'; + +/** + * Investigation guide, medium size, version C (version A that was modified in another way). + * Modification: "Investigating High Number" -> "Investigating Low Number". + */ +export const TEXT_M_C = + '## Triage and analysis\n\n### Investigating Low Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n'; + +/** + * Investigation guide, medium size, expected result of the algorithm applied to versions A, B, and C. + * Changes compared to version A: + * - last line has been removed + * - "Investigating High Number" -> "Investigating Low Number" + */ +export const TEXT_M_MERGED = + '## Triage and analysis\n\n### Investigating Low Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n'; + +/** + * Investigation guide, extral large size, version A (original). + */ +export const TEXT_XL_A = + '## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n'; + +/** + * Investigation guide, extral large size, version B (version A that was modified in one way). + * Modification: "Triage and analysis" -> "Triage or analysis". + */ +export const TEXT_XL_B = + '## Triage or analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n'; + +/** + * Investigation guide, extral large size, version C (version A that was modified in another way). + * Modification: "Investigating High Number" -> "Investigating Low Number". + */ +export const TEXT_XL_C = + '## Triage and analysis\n\n### Investigating Low Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n'; + +/** + * Investigation guide, extral large size, expected result of the algorithm applied to versions A, B, and C. + * Changes compared to version A: + * - "Triage and analysis" -> "Triage or analysis" + * - "Investigating High Number" -> "Investigating Low Number" + */ +export const TEXT_XL_MERGED = + '## Triage or analysis\n\n### Investigating Low Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n## Triage and analysis\n\n### Investigating High Number of Process and/or Service Terminations\n\nAttackers can stop services and kill processes for a variety of purposes. For example, they can stop services associated with business applications and databases to release the lock on files used by these applications so they may be encrypted, or stop security and backup solutions, etc.\n\nThis rule identifies a high number (10) of service and/or process terminations (stop, delete, or suspend) from the same host within a short time period.\n\n#### Possible investigation steps\n\n- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.\n- Identify the user account that performed the action and whether it should perform this kind of action.\n- Contact the account owner and confirm whether they are aware of this activity.\n- Investigate other alerts associated with the user/host during the past 48 hours.\n- Check if any files on the host machine have been encrypted.\n\n### False positive analysis\n\n- This activity is unlikely to happen legitimately. Benign true positives (B-TPs) can be added as exceptions if necessary.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Isolate the involved host to prevent further destructive behavior, which is commonly associated with this activity.\n- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.\n- Reimage the host operating system or restore it to the operational state.\n- If any other destructive action was identified on the host, it is recommended to prioritize the investigation and look for ransomware preparation and execution activities.\n- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.test.ts index dd1d6abaa04b0..72e87fde6ca2f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.test.ts @@ -13,13 +13,23 @@ import { ThreeWayDiffConflict, } from '../../../../../../../../common/api/detection_engine'; import { multiLineStringDiffAlgorithm } from './multi_line_string_diff_algorithm'; +import { + TEXT_M_A, + TEXT_M_B, + TEXT_M_C, + TEXT_M_MERGED, + TEXT_XL_A, + TEXT_XL_B, + TEXT_XL_C, + TEXT_XL_MERGED, +} from './multi_line_string_diff_algorithm.mock'; describe('multiLineStringDiffAlgorithm', () => { it('returns current_version as merged output if there is no update - scenario AAA', () => { const mockVersions: ThreeVersionsOf = { - base_version: 'My description.\nThis is a second line.', - current_version: 'My description.\nThis is a second line.', - target_version: 'My description.\nThis is a second line.', + base_version: TEXT_M_A, + current_version: TEXT_M_A, + target_version: TEXT_M_A, }; const result = multiLineStringDiffAlgorithm(mockVersions); @@ -36,9 +46,9 @@ describe('multiLineStringDiffAlgorithm', () => { it('returns current_version as merged output if current_version is different and there is no update - scenario ABA', () => { const mockVersions: ThreeVersionsOf = { - base_version: 'My description.\nThis is a second line.', - current_version: 'My GREAT description.\nThis is a second line.', - target_version: 'My description.\nThis is a second line.', + base_version: TEXT_M_A, + current_version: TEXT_M_B, + target_version: TEXT_M_A, }; const result = multiLineStringDiffAlgorithm(mockVersions); @@ -55,9 +65,9 @@ describe('multiLineStringDiffAlgorithm', () => { it('returns target_version as merged output if current_version is the same and there is an update - scenario AAB', () => { const mockVersions: ThreeVersionsOf = { - base_version: 'My description.\nThis is a second line.', - current_version: 'My description.\nThis is a second line.', - target_version: 'My GREAT description.\nThis is a second line.', + base_version: TEXT_M_A, + current_version: TEXT_M_A, + target_version: TEXT_M_B, }; const result = multiLineStringDiffAlgorithm(mockVersions); @@ -74,9 +84,9 @@ describe('multiLineStringDiffAlgorithm', () => { it('returns current_version as merged output if current version is different but it matches the update - scenario ABB', () => { const mockVersions: ThreeVersionsOf = { - base_version: 'My description.\nThis is a second line.', - current_version: 'My GREAT description.\nThis is a second line.', - target_version: 'My GREAT description.\nThis is a second line.', + base_version: TEXT_M_A, + current_version: TEXT_M_B, + target_version: TEXT_M_B, }; const result = multiLineStringDiffAlgorithm(mockVersions); @@ -92,20 +102,39 @@ describe('multiLineStringDiffAlgorithm', () => { }); describe('if all three versions are different - scenario ABC', () => { - it('returns a computated merged version without a conflict if 3 way merge is possible', () => { + it('returns a computated merged version with a solvable conflict if 3 way merge is possible (real-world example)', () => { const mockVersions: ThreeVersionsOf = { - base_version: `My description.\f\nThis is a second\u2001 line.\f\nThis is a third line.`, - current_version: `My GREAT description.\f\nThis is a second\u2001 line.\f\nThis is a third line.`, - target_version: `My description.\f\nThis is a second\u2001 line.\f\nThis is a GREAT line.`, + base_version: TEXT_M_A, + current_version: TEXT_M_B, + target_version: TEXT_M_C, }; - const expectedMergedVersion = `My GREAT description.\f\nThis is a second\u2001 line.\f\nThis is a GREAT line.`; + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: TEXT_M_MERGED, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + conflict: ThreeWayDiffConflict.SOLVABLE, + merge_outcome: ThreeWayMergeOutcome.Merged, + }) + ); + }); + + it('returns a computated merged version with a solvable conflict if 3 way merge is possible (simplified example)', () => { + // 3 way merge is possible when changes are made to different lines of text + // (in other words, there are no different changes made to the same line of text). + const mockVersions: ThreeVersionsOf = { + base_version: 'My description.\nThis is a second line.', + current_version: 'My MODIFIED description.\nThis is a second line.', + target_version: 'My description.\nThis is a MODIFIED second line.', + }; const result = multiLineStringDiffAlgorithm(mockVersions); expect(result).toEqual( expect.objectContaining({ - merged_version: expectedMergedVersion, + merged_version: 'My MODIFIED description.\nThis is a MODIFIED second line.', diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, conflict: ThreeWayDiffConflict.SOLVABLE, merge_outcome: ThreeWayMergeOutcome.Merged, @@ -113,11 +142,13 @@ describe('multiLineStringDiffAlgorithm', () => { ); }); - it('returns the current_version with a conflict if 3 way merge is not possible', () => { + it('returns the current_version with a non-solvable conflict if 3 way merge is not possible (simplified example)', () => { + // It's enough to have different changes made to the same line of text + // to trigger a NON_SOLVABLE conflict. This behavior is similar to how Git works. const mockVersions: ThreeVersionsOf = { base_version: 'My description.\nThis is a second line.', - current_version: 'My GREAT description.\nThis is a third line.', - target_version: 'My EXCELLENT description.\nThis is a fourth.', + current_version: 'My GREAT description.\nThis is a second line.', + target_version: 'My EXCELLENT description.\nThis is a second line.', }; const result = multiLineStringDiffAlgorithm(mockVersions); @@ -131,14 +162,39 @@ describe('multiLineStringDiffAlgorithm', () => { }) ); }); + + it('does not exceed performance limits when diffing and merging extra large input texts', () => { + const mockVersions: ThreeVersionsOf = { + base_version: TEXT_XL_A, + current_version: TEXT_XL_B, + target_version: TEXT_XL_C, + }; + + const startTime = performance.now(); + const result = multiLineStringDiffAlgorithm(mockVersions); + const endTime = performance.now(); + + // If the regex merge in this function takes over 500ms, this test fails + // Performance measurements: https://github.com/elastic/kibana/pull/199388 + expect(endTime - startTime).toBeLessThan(500); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: TEXT_XL_MERGED, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + conflict: ThreeWayDiffConflict.SOLVABLE, + merge_outcome: ThreeWayMergeOutcome.Merged, + }) + ); + }); }); describe('if base_version is missing', () => { it('returns current_version as merged output if current_version and target_version are the same - scenario -AA', () => { const mockVersions: ThreeVersionsOf = { base_version: MissingVersion, - current_version: 'My description.\nThis is a second line.', - target_version: 'My description.\nThis is a second line.', + current_version: TEXT_M_A, + target_version: TEXT_M_A, }; const result = multiLineStringDiffAlgorithm(mockVersions); @@ -158,8 +214,8 @@ describe('multiLineStringDiffAlgorithm', () => { it('returns target_version as merged output if current_version and target_version are different - scenario -AB', () => { const mockVersions: ThreeVersionsOf = { base_version: MissingVersion, - current_version: `My GREAT description.\nThis is a second line.`, - target_version: `My description.\nThis is a second line, now longer.`, + current_version: TEXT_M_A, + target_version: TEXT_M_B, }; const result = multiLineStringDiffAlgorithm(mockVersions); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.ts index ab830d1b7fc14..e09d8e110bff0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.ts @@ -102,7 +102,7 @@ const mergeVersions = ({ // TS does not realize that in ABC scenario, baseVersion cannot be missing // Missing baseVersion scenarios were handled as -AA and -AB. const mergedVersion = merge(currentVersion, baseVersion ?? '', targetVersion, { - stringSeparator: /(\S+|\s+)/g, // Retains all whitespace, which we keep to preserve formatting + stringSeparator: /(\r\n|\n|\r)/g, // Separates strings by new lines }); return mergedVersion.conflict diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts index a7072416a062e..bcff0417cdf9a 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts @@ -930,9 +930,33 @@ describe('TaskManagerRunner', () => { const loggerCall = logger.error.mock.calls[0][0]; const loggerMeta = logger.error.mock.calls[0][1]; expect(loggerCall as string).toMatchInlineSnapshot(`"Task bar \\"foo\\" failed: Error: rar"`); - expect(loggerMeta?.tags).toEqual(['bar', 'foo', 'task-run-failed']); + expect(loggerMeta?.tags).toEqual(['bar', 'foo', 'task-run-failed', 'framework-error']); expect(loggerMeta?.error?.stack_trace).toBeDefined(); }); + test('logs user errors as expected when task fails', async () => { + const { runner, logger } = await readyToRunStageSetup({ + instance: { + params: { a: 'b' }, + state: { hey: 'there' }, + }, + definitions: { + bar: { + title: 'Bar!', + createTaskRunner: () => ({ + async run() { + throw createTaskRunError(new Error('rar'), TaskErrorSource.USER); + }, + }), + }, + }, + }); + await runner.run(); + + const loggerCall = logger.error.mock.calls[0][0]; + const loggerMeta = logger.error.mock.calls[0][1]; + expect(loggerCall as string).toMatchInlineSnapshot(`"Task bar \\"foo\\" failed: Error: rar"`); + expect(loggerMeta?.tags).toEqual(['bar', 'foo', 'task-run-failed', 'user-error']); + }); test('provides execution context on run', async () => { const { runner } = await readyToRunStageSetup({ definitions: { diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.ts index 10fac96fe7c0a..9f9dadbc27c93 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.ts @@ -55,11 +55,12 @@ import { TaskStatus, } from '../task'; import { TaskTypeDictionary } from '../task_type_dictionary'; -import { isUnrecoverableError } from './errors'; +import { isUnrecoverableError, isUserError } from './errors'; import { CLAIM_STRATEGY_MGET, type TaskManagerConfig } from '../config'; import { TaskValidator } from '../task_validator'; import { getRetryAt, getRetryDate, getTimeout } from '../lib/get_retry_at'; import { getNextRunAt } from '../lib/get_next_run_at'; +import { TaskErrorSource } from '../../common/constants'; export const EMPTY_RUN_RESULT: SuccessfulRunResult = { state: {} }; @@ -397,8 +398,9 @@ export class TaskManagerRunner implements TaskRunner { if (apmTrans) apmTrans.end('success'); return processedResult; } catch (err) { + const errorSource = isUserError(err) ? TaskErrorSource.USER : TaskErrorSource.FRAMEWORK; this.logger.error(`Task ${this} failed: ${err}`, { - tags: [this.taskType, this.instance.task.id, 'task-run-failed'], + tags: [this.taskType, this.instance.task.id, 'task-run-failed', `${errorSource}-error`], error: { stack_trace: err.stack }, }); // in error scenario, we can not get the RunResult diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management_scheduled_at.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management_scheduled_at.ts index a70225035d03c..1a393b126dfda 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management_scheduled_at.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management_scheduled_at.ts @@ -14,7 +14,8 @@ export default function createTaskManagementScheduledAtTests({ getService }: Ftr const esArchiver = getService('esArchiver'); const retry = getService('retry'); - describe('task management scheduled at', () => { + // FLAKY: https://github.com/elastic/kibana/issues/198664 + describe.skip('task management scheduled at', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/task_manager_tasks'); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts index 55a924cc5e45c..d9c20fc28b43a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts @@ -10,6 +10,12 @@ import { ThreeWayDiffOutcome, ThreeWayMergeOutcome, } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { + TEXT_XL_A, + TEXT_XL_B, + TEXT_XL_C, + TEXT_XL_MERGED, +} from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.mock'; import { FtrProviderContext } from '../../../../../../ftr_provider_context'; import { deleteAllTimelines, @@ -249,6 +255,56 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); + + it('should handle long multi-line strings without timing out', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 1, + description: TEXT_XL_A, + }), + ]); + await installPrebuiltRules(es, supertest); + + // Customize a multi line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + description: TEXT_XL_B, + }); + + // Increment the version of the installed rule, update a multi line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + description: TEXT_XL_C, + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and multi line string field update has no conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.description).toEqual({ + base_version: TEXT_XL_A, + current_version: TEXT_XL_B, + target_version: TEXT_XL_C, + merged_version: TEXT_XL_MERGED, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, + conflict: ThreeWayDiffConflict.SOLVABLE, + has_update: true, + has_base_version: true, + }); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); }); describe('when all versions are not mergable', () => { diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_rules.ts index 038ed1787843a..2dc5358f0f7ad 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_rules.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_rules.ts @@ -1215,6 +1215,58 @@ export default ({ getService }: FtrProviderContext): void => { }); }); + it('should be able to import a rule with both single space and space agnostic exception lists', async () => { + const ndjson = combineToNdJson( + getCustomQueryRuleParams({ + exceptions_list: [ + { + id: 'agnostic', + list_id: 'test_list_agnostic_id', + type: 'detection', + namespace_type: 'agnostic', + }, + { + id: 'single', + list_id: 'test_list_id', + type: 'rule_default', + namespace_type: 'single', + }, + ], + }), + { ...getImportExceptionsListSchemaMock('test_list_id'), type: 'rule_default' }, + getImportExceptionsListItemNewerVersionSchemaMock('test_item_id', 'test_list_id'), + { + ...getImportExceptionsListSchemaMock('test_list_agnostic_id'), + type: 'detection', + namespace_type: 'agnostic', + }, + { + ...getImportExceptionsListItemNewerVersionSchemaMock( + 'test_item_id', + 'test_list_agnostic_id' + ), + namespace_type: 'agnostic', + } + ); + + const { body } = await supertest + .post(`${DETECTION_ENGINE_RULES_URL}/_import`) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .attach('file', Buffer.from(ndjson), 'rules.ndjson') + .expect(200); + + expect(body).toMatchObject({ + success: true, + success_count: 1, + rules_count: 1, + errors: [], + exceptions_errors: [], + exceptions_success: true, + exceptions_success_count: 2, + }); + }); + it('should only remove non existent exception list references from rule', async () => { // create an exception list const { body: exceptionBody } = await supertest diff --git a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/api_deprecations.ts b/x-pack/test/upgrade_assistant_integration/upgrade_assistant/api_deprecations.ts index bbce39e9fb29a..74c3064f9341d 100644 --- a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/api_deprecations.ts +++ b/x-pack/test/upgrade_assistant_integration/upgrade_assistant/api_deprecations.ts @@ -28,7 +28,8 @@ export default function ({ getService }: FtrProviderContext) { const retry = getService('retry'); const es = getService('es'); - describe('Kibana API Deprecations', function () { + // FLAKY: https://github.com/elastic/kibana/issues/199782 + describe.skip('Kibana API Deprecations', function () { // bail on first error in this suite since cases sequentially depend on each other this.bail(true); diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts b/x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts index 196de4506f38d..ae56c9fe4ece6 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts @@ -17,6 +17,7 @@ const enabledActionTypes = [ '.servicenow-itom', '.servicenow-sir', '.swimlane', + '.thehive', ]; export default createTestConfig({ diff --git a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/settings.ts b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/settings.ts index 63332200a9dd5..d692442c55717 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/settings.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/settings.ts @@ -10,21 +10,31 @@ import { FtrProviderContext } from '../../../../../ftr_provider_context'; import { navigateToCasesApp } from '../../../../../../shared/lib/cases'; export default function ({ getPageObject, getPageObjects, getService }: FtrProviderContext) { + const retry = getService('retry'); const svlCases = getService('svlCases'); const svlCommonScreenshots = getService('svlCommonScreenshots'); + const svlCommonPage = getPageObject('svlCommonPage'); const screenshotDirectories = ['response_ops_docs', 'observability_cases']; const testSubjects = getService('testSubjects'); const owner = OBSERVABILITY_OWNER; - // FLAKY:https://github.com/elastic/kibana/issues/189058 - describe.skip('Observability case settings', function () { + describe('Observability case settings', function () { + before(async () => { + await svlCommonPage.loginWithPrivilegedRole(); + }); after(async () => { await svlCases.api.deleteAllCaseItems(); }); it('case settings screenshots', async () => { await navigateToCasesApp(getPageObject, getService, owner); + await retry.waitFor('configure-case-button exist', async () => { + return await testSubjects.exists('configure-case-button'); + }); await testSubjects.click('configure-case-button'); + await retry.waitFor('add-custom-field exist', async () => { + return await testSubjects.exists('add-custom-field'); + }); await testSubjects.click('add-custom-field'); await svlCommonScreenshots.takeScreenshot( 'observability-cases-custom-fields', @@ -33,11 +43,17 @@ export default function ({ getPageObject, getPageObjects, getService }: FtrProvi 700 ); await testSubjects.setValue('custom-field-label-input', 'my-field'); + await retry.waitFor('common-flyout-save exist', async () => { + return await testSubjects.exists('common-flyout-save'); + }); await testSubjects.click('common-flyout-save'); await svlCommonScreenshots.takeScreenshot( 'observability-cases-settings', screenshotDirectories ); + await retry.waitFor('add-template exist', async () => { + return await testSubjects.exists('add-template'); + }); await testSubjects.click('add-template'); await svlCommonScreenshots.takeScreenshot( 'observability-cases-templates', @@ -45,13 +61,21 @@ export default function ({ getPageObject, getPageObjects, getService }: FtrProvi 1400, 1000 ); + await retry.waitFor('common-flyout-cancel exist', async () => { + return await testSubjects.exists('common-flyout-cancel'); + }); await testSubjects.click('common-flyout-cancel'); - await testSubjects.click('dropdown-connectors'); - await testSubjects.click('dropdown-connector-add-connector'); + await retry.waitFor('dropdown-connectors exist', async () => { + return await testSubjects.exists('dropdown-connectors'); + }); + await testSubjects.click('add-new-connector'); await svlCommonScreenshots.takeScreenshot( 'observability-cases-add-connector', screenshotDirectories ); + await retry.waitFor('euiFlyoutCloseButton exist', async () => { + return await testSubjects.exists('euiFlyoutCloseButton'); + }); await testSubjects.click('euiFlyoutCloseButton'); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/settings.ts b/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/settings.ts index 76dd5529cbafc..59e1adab34078 100644 --- a/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/settings.ts +++ b/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/settings.ts @@ -11,14 +11,14 @@ import { navigateToCasesApp } from '../../../../../../shared/lib/cases'; export default function ({ getPageObject, getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects(['common', 'header', 'svlCommonPage', 'svlCommonNavigation']); + const retry = getService('retry'); const svlCases = getService('svlCases'); const svlCommonScreenshots = getService('svlCommonScreenshots'); const screenshotDirectories = ['response_ops_docs', 'security_cases']; const testSubjects = getService('testSubjects'); const owner = SECURITY_SOLUTION_OWNER; - // FLAKY: https://github.com/elastic/kibana/issues/188997 - describe.skip('security case settings', function () { + describe('security case settings', function () { after(async () => { await svlCases.api.deleteAllCaseItems(); }); @@ -29,8 +29,14 @@ export default function ({ getPageObject, getPageObjects, getService }: FtrProvi it('case settings screenshot', async () => { await navigateToCasesApp(getPageObject, getService, owner); + await retry.waitFor('configure-case-button exist', async () => { + return await testSubjects.exists('configure-case-button'); + }); await testSubjects.click('configure-case-button'); await pageObjects.header.waitUntilLoadingHasFinished(); + await retry.waitFor('add-custom-field exist', async () => { + return await testSubjects.exists('add-custom-field'); + }); await testSubjects.click('add-custom-field'); await svlCommonScreenshots.takeScreenshot( 'security-cases-custom-fields', @@ -38,9 +44,18 @@ export default function ({ getPageObject, getPageObjects, getService }: FtrProvi 1400, 700 ); + await retry.waitFor('custom-field-label-input exist', async () => { + return await testSubjects.exists('custom-field-label-input'); + }); await testSubjects.setValue('custom-field-label-input', 'my-field'); + await retry.waitFor('common-flyout-save exist', async () => { + return await testSubjects.exists('common-flyout-save'); + }); await testSubjects.click('common-flyout-save'); await svlCommonScreenshots.takeScreenshot('security-cases-settings', screenshotDirectories); + await retry.waitFor('add-template to exist', async () => { + return await testSubjects.exists('add-template'); + }); await testSubjects.click('add-template'); await svlCommonScreenshots.takeScreenshot( 'security-cases-templates', @@ -48,11 +63,10 @@ export default function ({ getPageObject, getPageObjects, getService }: FtrProvi 1400, 1000 ); + await retry.waitFor('common-flyout-cancel to exist', async () => { + return await testSubjects.exists('common-flyout-cancel'); + }); await testSubjects.click('common-flyout-cancel'); - await testSubjects.click('dropdown-connectors'); - await testSubjects.click('dropdown-connector-add-connector'); - await svlCommonScreenshots.takeScreenshot('security-cases-connectors', screenshotDirectories); - await testSubjects.click('euiFlyoutCloseButton'); }); }); } diff --git a/yarn.lock b/yarn.lock index 8e2333250dd7d..a6befe6cf3110 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5914,7 +5914,15 @@ version "0.0.0" uid "" -"@kbn/observability-utils@link:x-pack/packages/observability/observability_utils": +"@kbn/observability-utils-browser@link:x-pack/packages/observability/observability_utils/observability_utils_browser": + version "0.0.0" + uid "" + +"@kbn/observability-utils-common@link:x-pack/packages/observability/observability_utils/observability_utils_common": + version "0.0.0" + uid "" + +"@kbn/observability-utils-server@link:x-pack/packages/observability/observability_utils/observability_utils_server": version "0.0.0" uid ""