From 678ffa0bfe50419720075e45ce315eea3da33d2a Mon Sep 17 00:00:00 2001 From: Jedr Blaszyk Date: Thu, 6 Jun 2024 10:43:37 +0200 Subject: [PATCH 01/87] [Connectors] Use Connector API to create a connector (#183398) ## Summary Use [Connector API endpoint](https://www.elastic.co/guide/en/elasticsearch/reference/master/create-connector-api.html) in the create connectors action. Note: https://github.com/elastic/elasticsearch/pull/109248 was merged into ES very recently, you might need to pull latest ES image to get this working. Note: some crawler features also utilise connector index, since it was agreed not to support those features in the Connector API I'm leaving crawler related logic unchanged ### Validation - Add unit tests - Test locally with stack - Test locally with serverless --- .../lib/create_connector.test.ts | 198 ++++++++++++++++++ .../lib/create_connector.ts | 51 +++-- .../utils/connector_status_helpers.ts | 14 +- .../server/routes/connectors_routes.ts | 1 - 4 files changed, 245 insertions(+), 19 deletions(-) create mode 100644 packages/kbn-search-connectors/lib/create_connector.test.ts diff --git a/packages/kbn-search-connectors/lib/create_connector.test.ts b/packages/kbn-search-connectors/lib/create_connector.test.ts new file mode 100644 index 0000000000000..66d8ce226c1a8 --- /dev/null +++ b/packages/kbn-search-connectors/lib/create_connector.test.ts @@ -0,0 +1,198 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { errors } from '@elastic/elasticsearch'; + +import { ElasticsearchClient } from '@kbn/core/server'; +import { FeatureName } from '../types'; + +import { createConnector } from './create_connector'; + +const notFoundError = new errors.ResponseError({ + statusCode: 404, + body: { + error: { + type: `document_missing_exception`, + }, + }, +} as any); + +describe('createConnector lib', () => { + const mockClient = { + transport: { + request: jest.fn(), + }, + }; + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should create connector with _connector API endpoint', async () => { + const connectorId = 'connectorId'; + const mockConnector = { + id: connectorId, + index_name: 'indexName', + language: 'en', + is_native: true, + }; + mockClient.transport.request + .mockResolvedValueOnce({ id: connectorId }) + .mockResolvedValueOnce(mockConnector); + + await expect( + createConnector(mockClient as unknown as ElasticsearchClient, { + isNative: true, + indexName: mockConnector.index_name, + language: mockConnector.language, + }) + ).resolves.toEqual(mockConnector); + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'POST', + path: `/_connector`, + body: { + index_name: 'indexName', + language: 'en', + is_native: true, + name: '', + }, + }); + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'GET', + path: `/_connector/${connectorId}`, + }); + }); + + it('should update pipeline params if provided', async () => { + const connectorId = 'connectorId'; + const mockConnector = { + id: connectorId, + index_name: 'indexName', + language: 'en', + is_native: true, + }; + + const mockPipeline = { + extract_binary_content: true, + name: 'test', + reduce_whitespace: true, + run_ml_inference: true, + }; + + mockClient.transport.request + .mockResolvedValueOnce({ id: connectorId }) + .mockResolvedValueOnce({ result: 'updated' }) + .mockResolvedValueOnce(mockConnector); + + await expect( + createConnector(mockClient as unknown as ElasticsearchClient, { + isNative: true, + indexName: 'indexName', + language: 'en', + pipeline: mockPipeline, + }) + ).resolves.toEqual(mockConnector); + + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'POST', + path: `/_connector`, + body: { + index_name: 'indexName', + language: 'en', + is_native: true, + name: '', + }, + }); + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'PUT', + path: `/_connector/${connectorId}/_pipeline`, + body: { pipeline: mockPipeline }, + }); + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'GET', + path: `/_connector/${connectorId}`, + }); + }); + + it('should update connector features if provided', async () => { + const connectorId = 'connectorId'; + const mockConnector = { + id: connectorId, + index_name: 'indexName', + language: 'en', + is_native: true, + }; + + const mockFeatures = { + [FeatureName.FILTERING_ADVANCED_CONFIG]: true, + [FeatureName.FILTERING_RULES]: true, + [FeatureName.SYNC_RULES]: { + advanced: { enabled: true }, + basic: { enabled: true }, + }, + }; + + mockClient.transport.request + .mockResolvedValueOnce({ id: connectorId }) + .mockResolvedValueOnce({ result: 'updated' }) + .mockResolvedValueOnce(mockConnector); + + await expect( + createConnector(mockClient as unknown as ElasticsearchClient, { + isNative: true, + indexName: 'indexName', + language: 'en', + features: mockFeatures, + }) + ).resolves.toEqual(mockConnector); + + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'POST', + path: `/_connector`, + body: { + index_name: 'indexName', + language: 'en', + is_native: true, + name: '', + }, + }); + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'PUT', + path: `/_connector/${connectorId}/_features`, + body: { features: mockFeatures }, + }); + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'GET', + path: `/_connector/${connectorId}`, + }); + }); + + it('should throw an error if connector doc is not found', async () => { + mockClient.transport.request + .mockResolvedValueOnce({ id: 'connectorId' }) + .mockRejectedValueOnce(notFoundError); + + await expect( + createConnector(mockClient as unknown as ElasticsearchClient, { + isNative: true, + indexName: 'some-index', + language: 'somelang', + }) + ).rejects.toEqual(new Error('Could not retrieve the created connector')); + + expect(mockClient.transport.request).toHaveBeenCalledWith({ + method: 'POST', + path: `/_connector`, + body: { + index_name: 'some-index', + is_native: true, + language: 'somelang', + name: '', + }, + }); + }); +}); diff --git a/packages/kbn-search-connectors/lib/create_connector.ts b/packages/kbn-search-connectors/lib/create_connector.ts index 524fc3c195eac..666011e50f341 100644 --- a/packages/kbn-search-connectors/lib/create_connector.ts +++ b/packages/kbn-search-connectors/lib/create_connector.ts @@ -7,10 +7,10 @@ */ import { ElasticsearchClient } from '@kbn/core/server'; -import { CURRENT_CONNECTORS_INDEX } from '..'; +import { i18n } from '@kbn/i18n'; +import { fetchConnectorById } from '..'; import { Connector, ConnectorConfiguration, IngestPipelineParams } from '../types/connectors'; -import { createConnectorDocument } from './create_connector_document'; export const createConnector = async ( client: ElasticsearchClient, @@ -23,19 +23,46 @@ export const createConnector = async ( name?: string; pipeline?: IngestPipelineParams; serviceType?: string | null; - instant_response?: boolean; } ): Promise => { - const document = createConnectorDocument({ - ...input, - serviceType: input.serviceType || null, + const { id: connectorId } = await client.transport.request<{ id: string }>({ + method: 'POST', + path: `/_connector`, + body: { + ...(input.indexName && { index_name: input.indexName }), + is_native: input.isNative, + ...(input.language && { language: input.language }), + name: input.name || '', + ...(input.serviceType && { service_type: input.serviceType }), + }, }); - const result = await client.index({ - document, - index: CURRENT_CONNECTORS_INDEX, - refresh: input.instant_response ? false : 'wait_for', - }); + if (input.pipeline) { + await client.transport.request({ + method: 'PUT', + path: `/_connector/${connectorId}/_pipeline`, + body: { pipeline: input.pipeline }, + }); + } + + if (input.features) { + await client.transport.request({ + method: 'PUT', + path: `/_connector/${connectorId}/_features`, + body: { features: input.features }, + }); + } + + // createConnector function expects to return a Connector doc, so we fetch it from the index + const connector = await fetchConnectorById(client, connectorId); + + if (!connector) { + throw new Error( + i18n.translate('searchConnectors.server.connectors.not_found_error', { + defaultMessage: 'Could not retrieve the created connector', + }) + ); + } - return { ...document, id: result._id }; + return connector; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/utils/connector_status_helpers.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/utils/connector_status_helpers.ts index 52d59ae81ccef..c9e2bb0dd2b45 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/utils/connector_status_helpers.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/utils/connector_status_helpers.ts @@ -44,9 +44,10 @@ export function connectorStatusToText(connector: Connector): string { ); } if ( - connector.error === SyncStatus.ERROR || - connector.last_sync_error !== null || - connector.last_access_control_sync_error !== null + connector.last_sync_status === SyncStatus.ERROR || + connector.last_access_control_sync_status === SyncStatus.ERROR || + connector.last_sync_error != null || + connector.last_access_control_sync_error != null ) { return i18n.translate( 'xpack.enterpriseSearch.content.searchIndices.connectorStatus.syncFailure.label', @@ -87,9 +88,10 @@ export function connectorStatusToColor(connector: Connector): 'warning' | 'dange if ( isLastSeenOld(connector) || connectorStatus === ConnectorStatus.ERROR || - connector.error === SyncStatus.ERROR || - connector.last_sync_error !== null || - connector.last_access_control_sync_error !== null + connector.last_sync_status === SyncStatus.ERROR || + connector.last_access_control_sync_status === SyncStatus.ERROR || + connector.last_sync_error != null || + connector.last_access_control_sync_error != null ) { return 'danger'; } diff --git a/x-pack/plugins/serverless_search/server/routes/connectors_routes.ts b/x-pack/plugins/serverless_search/server/routes/connectors_routes.ts index af54d4ccb6d56..36d9a48bedffb 100644 --- a/x-pack/plugins/serverless_search/server/routes/connectors_routes.ts +++ b/x-pack/plugins/serverless_search/server/routes/connectors_routes.ts @@ -73,7 +73,6 @@ export const registerConnectorsRoutes = ({ http, router }: RouteDependencies) => const { client } = (await context.core).elasticsearch; const connector = await createConnector(client.asCurrentUser, { indexName: null, - instant_response: true, isNative: false, language: null, }); From 2a56861b49814c0a9c02163a83dd588d7cb9d973 Mon Sep 17 00:00:00 2001 From: elena-shostak <165678770+elena-shostak@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:41:32 +0200 Subject: [PATCH 02/87] [Roles] ComboBox overflow fix (#184722) ## Summary Fixed `ComboBox` overflow with large chips. Applies to the following fields: - Indices. - Remote indices. - Remote clusters. Screenshot 2024-06-04 at 11 43 39 https://github.com/elastic/kibana/assets/165678770/f6bbc325-a957-4c3e-bc88-721b77dc8ff0 Options considered: 1. **Flex with specific grow attribute set**. This will not stop the `ComboBox` from growing after it reaches 50% point of available space. ``` ... ... ``` 2. **Grid with columns.** ``` ... ... ``` CSS is the following. ``` grid-template-columns: repeat(2, 1fr); ``` The problem is that `1fr` is about the distribution of available space, as soon as content of `ComboBox` becomes bigger it breaks. 3. **Combobox props.** We have `fullWidth` attribute set that we need for stretching to available column space, so the content doesn't wrap unless there is the `maxWidth` set for column. Alternative is to remove `fullWidth` which wraps chips correctly, but then doesn't satisfy the design. 4. **`maxWidth` for `EuiFlexItem`.** ``` ... ... ``` That option works, but since we have the same form for index privileges and remote index privileges, we would need to justify it for 2 columns (maxWidth: '50%' ), 3 columns (maxWidth: '33%' ) and mobile accordingly (maxWidth: '100%' ). Can be less scalable. 4. Leverage grid `minmax`. ``` grid-template-columns: repeat(N, minmax(0, 1fr)); ``` It allows to create columns as large as `1fr` and not exceed it, so `ComboBox` will nicely fit. ### Checklist - [x] [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 - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [x] 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)) - [x] 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)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) __Fixes: https://github.com/elastic/kibana/issues/183311__ ### Release note Fixed `ComboBox` overflow with large chips. --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../index_privilege_form.test.tsx.snap | 22 +++++++++++++++++-- ...mote_cluster_privileges_form.test.tsx.snap | 19 ++++++++++++++-- .../privileges/es/index_privilege_form.tsx | 17 ++++++++++++-- .../es/remote_cluster_privileges_form.tsx | 14 ++++++++++-- 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/index_privilege_form.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/index_privilege_form.test.tsx.snap index 7080b6a70be9b..5107e8abf2e0b 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/index_privilege_form.test.tsx.snap +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/index_privilege_form.test.tsx.snap @@ -14,7 +14,25 @@ exports[`it renders without crashing 1`] = ` - + - + - + - + { private getPrivilegeForm = () => { return ( <> - + {this.props.indexType === 'remote_indices' ? ( { /> - + {this.getFieldLevelControls()} {this.getGrantedDocumentsControl()} diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/remote_cluster_privileges_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/remote_cluster_privileges_form.tsx index 5e55ebaf1d281..7f406df106f72 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/remote_cluster_privileges_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/remote_cluster_privileges_form.tsx @@ -9,17 +9,20 @@ import type { EuiComboBoxOptionOption } from '@elastic/eui'; import { EuiButtonIcon, EuiComboBox, + EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiPanel, EuiSpacer, } from '@elastic/eui'; +import { css } from '@emotion/react'; import React, { Fragment, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { Cluster } from '@kbn/remote-clusters-plugin/public'; +import { euiThemeVars } from '@kbn/ui-theme'; import { RemoteClusterComboBox } from './remote_clusters_combo_box'; import type { RoleRemoteClusterPrivilege } from '../../../../../../common'; @@ -92,7 +95,14 @@ export const RemoteClusterPrivilegesForm: React.FunctionComponent = ({ > - + = ({ /> - + {!isRoleReadOnly && ( From dd999bbd29fbc3d1d7bef7fc70c3e9246780dba6 Mon Sep 17 00:00:00 2001 From: Luke G <11671118+lgestc@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:55:11 +0200 Subject: [PATCH 03/87] [Security Solution] Toggle new sourcerer implementation with local storage switch (#184822) ## Summary Add `localStorage` based mechanism to toggle between the future experiemental sourcerer implementation and the stable one in **runtime**. Also moved the hook for pulling in the data from the sourcerer to appropriately named file. --- .../public/sourcerer/containers/index.tsx | 9 ++++++- .../sourcerer/experimental/is_enabled.ts | 16 +++++++++++++ .../public/sourcerer/experimental/readme.md | 18 ++++++++++++++ ...se_unstable_security_solution_data_view.ts | 24 +++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/security_solution/public/sourcerer/experimental/is_enabled.ts create mode 100644 x-pack/plugins/security_solution/public/sourcerer/experimental/readme.md create mode 100644 x-pack/plugins/security_solution/public/sourcerer/experimental/use_unstable_security_solution_data_view.ts diff --git a/x-pack/plugins/security_solution/public/sourcerer/containers/index.tsx b/x-pack/plugins/security_solution/public/sourcerer/containers/index.tsx index a9cf833696a57..a8dc888541f33 100644 --- a/x-pack/plugins/security_solution/public/sourcerer/containers/index.tsx +++ b/x-pack/plugins/security_solution/public/sourcerer/containers/index.tsx @@ -15,6 +15,7 @@ import { getDataViewStateFromIndexFields } from '../../common/containers/source/ import { useFetchIndex } from '../../common/containers/source'; import type { State } from '../../common/store/types'; import { sortWithExcludesAtEnd } from '../../../common/utils/sourcerer'; +import { useUnstableSecuritySolutionDataView } from '../experimental/use_unstable_security_solution_data_view'; export const useSourcererDataView = ( scopeId: SourcererScopeName = SourcererScopeName.default @@ -114,7 +115,7 @@ export const useSourcererDataView = ( return dataViewBrowserFields; }, [sourcererDataView.fields, sourcererDataView.patternList]); - return useMemo( + const stableSourcererValues = useMemo( () => ({ browserFields: browserFields(), dataViewId: sourcererDataView.id, @@ -143,4 +144,10 @@ export const useSourcererDataView = ( legacyPatterns.length, ] ); + + return useUnstableSecuritySolutionDataView( + scopeId, + // NOTE: data view derived from current implementation is used as a fallback + stableSourcererValues + ); }; diff --git a/x-pack/plugins/security_solution/public/sourcerer/experimental/is_enabled.ts b/x-pack/plugins/security_solution/public/sourcerer/experimental/is_enabled.ts new file mode 100644 index 0000000000000..efdc2c7468847 --- /dev/null +++ b/x-pack/plugins/security_solution/public/sourcerer/experimental/is_enabled.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. + */ + +/** + * Allows toggling between sourcerer implementations in runtime. Simply set the value in local storage + * to: + * - display the experimental component instead of the stable one + * - use experimental data views hook instead of the stable one + */ +export const IS_EXPERIMENTAL_SOURCERER_ENABLED = !!window.localStorage.getItem( + 'EXPERIMENTAL_SOURCERER_ENABLED' +); diff --git a/x-pack/plugins/security_solution/public/sourcerer/experimental/readme.md b/x-pack/plugins/security_solution/public/sourcerer/experimental/readme.md new file mode 100644 index 0000000000000..077bef147cbed --- /dev/null +++ b/x-pack/plugins/security_solution/public/sourcerer/experimental/readme.md @@ -0,0 +1,18 @@ +# Experimental Sourcerer Replacement + +## Introduction + +This directory is a home for Discovery Components based re-implementation of the Sourcerer. + +Currently, it can be enabled and used only by setting the localStorage value, like this: + +``` +window.localStorage.setItem('EXPERIMENTAL_SOURCERER_ENABLED', true) +``` + +The reason for having this feature toggle like this is we want to be able to inspect both implementations side by side, +using the same Kibana instance deployed locally (for now). + +## Architecture + +TODO diff --git a/x-pack/plugins/security_solution/public/sourcerer/experimental/use_unstable_security_solution_data_view.ts b/x-pack/plugins/security_solution/public/sourcerer/experimental/use_unstable_security_solution_data_view.ts new file mode 100644 index 0000000000000..a841834a8b1fe --- /dev/null +++ b/x-pack/plugins/security_solution/public/sourcerer/experimental/use_unstable_security_solution_data_view.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 SourcererScopeName, type SelectedDataView } from '../store/model'; + +import { IS_EXPERIMENTAL_SOURCERER_ENABLED } from './is_enabled'; + +/** + * FOR INTERNAL USE ONLY + * This hook provides data for experimental Sourcerer replacement in Security Solution. + * Do not use in client code as the API will change frequently. + * It will be extended in the future, covering more and more functionality from the current sourcerer. + */ +export const useUnstableSecuritySolutionDataView = ( + _scopeId: SourcererScopeName, + fallbackDataView: SelectedDataView +): SelectedDataView => { + // TODO: extend the fallback state with values computed using new logic + return IS_EXPERIMENTAL_SOURCERER_ENABLED ? fallbackDataView : fallbackDataView; +}; From 28a01c142404f9524bd8e1676f848bf75af594a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Thu, 6 Jun 2024 11:05:12 +0100 Subject: [PATCH 04/87] [Project sidenav] Refactor NavigationSectionUI component (#184745) --- .../project_navigation_service.test.ts | 28 -- .../project_navigation_service.ts | 78 +-- .../core/chrome/core-chrome-browser/index.ts | 1 + .../chrome/core-chrome-browser/src/index.ts | 1 + .../ui/components/navigation_section_ui.tsx | 473 ++++++------------ .../chrome/navigation/src/ui/constants.ts | 13 + .../chrome/navigation/src/ui/hooks/index.ts | 9 + .../src/ui/hooks/use_accordion_state.ts | 181 +++++++ .../chrome/navigation/src/ui/types.ts | 53 +- .../shared-ux/chrome/navigation/src/utils.ts | 6 + .../test_suites/observability/navigation.ts | 1 - .../test_suites/search/navigation.ts | 1 - 12 files changed, 383 insertions(+), 462 deletions(-) create mode 100644 packages/shared-ux/chrome/navigation/src/ui/constants.ts create mode 100644 packages/shared-ux/chrome/navigation/src/ui/hooks/index.ts create mode 100644 packages/shared-ux/chrome/navigation/src/ui/hooks/use_accordion_state.ts diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts index b9cca3027f2fc..e8dd64aab41b0 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts @@ -1002,32 +1002,4 @@ describe('solution navigations', () => { expect(activeSolution).toEqual(solution1); } }); - - it('should change the active solution if no node match the current Location', async () => { - const { projectNavigation, navLinksService, application } = setup({ - locationPathName: '/app/app3', // we are on app3 which only exists in solution3 - navLinkIds: ['app1', 'app2', 'app3'], - }); - - navLinksService.get.mockReturnValue({ url: '/app/app3', href: '/app/app3' } as any); - - const getActiveDefinition = () => - firstValueFrom(projectNavigation.getActiveSolutionNavDefinition$()); - - projectNavigation.updateSolutionNavigations({ solution1, solution2, solution3 }); - - { - const definition = await getActiveDefinition(); - expect(definition).toBe(null); // No active solution id yet - } - - // Change to solution 2, but we are still on '/app/app3' which only exists in solution3 - projectNavigation.changeActiveSolutionNavigation('solution2'); - - { - const definition = await getActiveDefinition(); - expect(definition?.id).toBe('solution3'); // The solution3 was activated as it matches the "/app/app3" location - expect(application.navigateToUrl).toHaveBeenCalled(); // Redirect - } - }); }); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts index 892ae29ed6862..0a1292be9b3f1 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts @@ -32,7 +32,6 @@ import { of, type Observable, type Subscription, - take, } from 'rxjs'; import { type Location, createLocation } from 'history'; import deepEqual from 'react-fast-compare'; @@ -224,22 +223,9 @@ export class ProjectNavigationService { this.navigationTree$.next(navigationTree); this.navigationTreeUi$.next(navigationTreeUI); this.projectNavigationNavTreeFlattened = flattenNav(navigationTree); + this.updateActiveProjectNavigationNodes(); - // Verify if the current location is part of the navigation tree of - // the initiated solution. If not, we need to find the correct solution - const activeNodes = this.updateActiveProjectNavigationNodes(); - let willChangeSolution = false; - - if (activeNodes.length === 0) { - const solutionForCurrentLocation = this.findSolutionForCurrentLocation(); - if (solutionForCurrentLocation) { - willChangeSolution = true; - this.goToSolutionHome(solutionForCurrentLocation); - this.changeActiveSolutionNavigation(solutionForCurrentLocation); - } - } - - if (!initialised && !willChangeSolution) { + if (!initialised) { this.activeSolutionNavDefinitionId$.next(id); initialised = true; } @@ -318,48 +304,6 @@ export class ProjectNavigationService { }); } - /** - * When we are in stateful Kibana with multiple solution navigations, it is possible that a user - * lands on a page that does not belong to the current active solution navigation. In this case, - * we need to find the correct solution navigation based on the current location and switch to it. - */ - private findSolutionForCurrentLocation(): string | null { - if (Object.keys(this.solutionNavDefinitions$.getValue()).length === 0) return null; - - let idFound: string | null = null; - - combineLatest([this.solutionNavDefinitions$, this.location$]) - .pipe(take(1)) - .subscribe(([definitions, location]) => { - Object.entries(definitions).forEach(([id, definition]) => { - if (idFound) return; - - combineLatest([definition.navigationTree$, this.deepLinksMap$, this.cloudLinks$]) - .pipe( - take(1), - map(([def, deepLinksMap, cloudLinks]) => - parseNavigationTree(def, { - deepLinks: deepLinksMap, - cloudLinks, - }) - ) - ) - .subscribe(({ navigationTree }) => { - const maybeActiveNodes = this.findActiveNodes({ - location, - flattendTree: flattenNav(navigationTree), - }); - - if (maybeActiveNodes.length > 0) { - idFound = id; - } - }); - }); - }); - - return idFound; - } - private setSideNavComponent(component: SideNavComponent | null) { this.customProjectSideNavComponent$.next({ current: component }); } @@ -400,24 +344,6 @@ export class ProjectNavigationService { this.projectHome$.next(homeHref); } - private goToSolutionHome(id: string) { - const definitions = this.solutionNavDefinitions$.getValue(); - const definition = definitions[id]; - if (!definition) { - throw new Error(`No solution navigation definition found for id ${id}`); - } - - // Navigate to the new home page if it's defined - const link = this.navLinksService?.get(definition.homePage ?? 'undefined'); - if (!link) { - throw new Error(`No home page defined for solution navigation ${definition.id}`); - } - - const location = createLocation(link.url); - this.location$.next(location); - this.application?.navigateToUrl(link.url); - } - private changeActiveSolutionNavigation(id: string | null) { if (this.nextSolutionNavDefinitionId$.getValue() === id) return; this.nextSolutionNavDefinitionId$.next(id); diff --git a/packages/core/chrome/core-chrome-browser/index.ts b/packages/core/chrome/core-chrome-browser/index.ts index 27c20f502bc06..32b889ea7979d 100644 --- a/packages/core/chrome/core-chrome-browser/index.ts +++ b/packages/core/chrome/core-chrome-browser/index.ts @@ -57,4 +57,5 @@ export type { SolutionNavigationDefinition, SolutionNavigationDefinitions, EuiSideNavItemTypeEnhanced, + RenderAs, } from './src'; diff --git a/packages/core/chrome/core-chrome-browser/src/index.ts b/packages/core/chrome/core-chrome-browser/src/index.ts index a287499cd73ff..d3ac70d6520b8 100644 --- a/packages/core/chrome/core-chrome-browser/src/index.ts +++ b/packages/core/chrome/core-chrome-browser/src/index.ts @@ -56,4 +56,5 @@ export type { SolutionNavigationDefinition, SolutionNavigationDefinitions, EuiSideNavItemTypeEnhanced, + RenderAs, } from './project_navigation'; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx index 37297e3f25c0e..3d549cf663703 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx @@ -6,14 +6,12 @@ * Side Public License, v 1. */ -import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import classNames from 'classnames'; +import React, { type FC, useMemo, useEffect, useState, useCallback } from 'react'; import { css } from '@emotion/css'; import { EuiTitle, EuiCollapsibleNavItem, EuiSpacer, - type EuiAccordionProps, type EuiCollapsibleNavItemProps, type EuiCollapsibleNavSubItemProps, } from '@elastic/eui'; @@ -22,36 +20,31 @@ import classnames from 'classnames'; import type { EuiThemeSize, RenderAs } from '@kbn/core-chrome-browser/src/project_navigation'; import { useNavigation as useServices } from '../../services'; -import { isAbsoluteLink, isActiveFromUrl } from '../../utils'; +import { isAbsoluteLink, isActiveFromUrl, isAccordionNode } from '../../utils'; import type { NavigateToUrlFn } from '../../types'; import { useNavigation } from '../navigation'; +import { useAccordionState } from '../hooks'; +import { + DEFAULT_IS_COLLAPSIBLE, + DEFAULT_RENDER_AS, + DEFAULT_SPACE_BETWEEN_LEVEL_1_GROUPS, +} from '../constants'; +import type { EuiCollapsibleNavSubItemPropsEnhanced } from '../types'; import { PanelContext, usePanel } from './panel'; import { NavigationItemOpenPanel } from './navigation_item_open_panel'; -type EuiCollapsibleNavSubItemPropsEnhanced = EuiCollapsibleNavSubItemProps & { path?: string }; - -const DEFAULT_SPACE_BETWEEN_LEVEL_1_GROUPS: EuiThemeSize = 'm'; -const DEFAULT_IS_COLLAPSED = true; -const DEFAULT_IS_COLLAPSIBLE = true; -const DEFAULT_RENDER_AS: RenderAs = 'block'; - const nodeHasLink = (navNode: ChromeProjectNavigationNode) => Boolean(navNode.deepLink) || Boolean(navNode.href); const nodeHasChildren = (navNode: ChromeProjectNavigationNode) => Boolean(navNode.children?.length); -/** - * Predicate to determine if a node should be visible in the main side nav. - * If it is not visible it will be filtered out and not rendered. - */ +/** Predicate to determine if a node should be visible in the main side nav.*/ const itemIsVisible = (item: ChromeProjectNavigationNode) => { if (item.sideNavStatus === 'hidden') return false; if (item.renderItem) return true; - if (nodeHasLink(item)) { - return true; - } + if (nodeHasLink(item)) return true; if (nodeHasChildren(item)) { return item.renderAs === 'item' ? true : item.children!.some(itemIsVisible); @@ -75,17 +68,10 @@ const getTestSubj = (navNode: ChromeProjectNavigationNode, isActive = false): st }); }; -const filterChildren = ( - children?: ChromeProjectNavigationNode[] -): ChromeProjectNavigationNode[] | undefined => { - if (!children) return undefined; - return children.filter(itemIsVisible); -}; - const serializeNavNode = (navNode: ChromeProjectNavigationNode) => { const serialized: ChromeProjectNavigationNode = { ...navNode, - children: filterChildren(navNode.children), + children: navNode.children?.filter(itemIsVisible), }; serialized.renderAs = getRenderAs(serialized); @@ -94,7 +80,7 @@ const serializeNavNode = (navNode: ChromeProjectNavigationNode) => { navNode: serialized, hasChildren: nodeHasChildren(serialized), hasLink: nodeHasLink(serialized), - isItem: serialized.renderAs === 'item' || serialized.children === undefined, + isItem: serialized.renderAs === 'item', }; }; @@ -156,58 +142,69 @@ const renderGroup = ( return [itemPrepend, ...groupItems]; }; -const isAccordionNode = ( - node: Pick -) => - node.renderAs === 'accordion' || - ['defaultIsCollapsed', 'isCollapsible'].some((prop) => node.hasOwnProperty(prop)); - -// Generate the EuiCollapsible props for both the root component (EuiCollapsibleNavItem) and its -// "items" props. Both are compatible with the exception of "renderItem" which is only used for -// sub items. -const nodeToEuiCollapsibleNavProps = ( - _navNode: ChromeProjectNavigationNode, +const renderPanelOpener = ( + navGroup: ChromeProjectNavigationNode, { + spaceBefore, navigateToUrl, - openPanel, - closePanel, - isSideNavCollapsed, - treeDepth, - itemsAccordionState, activeNodes, }: { + spaceBefore?: EuiThemeSize | null; + navigateToUrl: NavigateToUrlFn; + activeNodes: ChromeProjectNavigationNode[][]; + } +): Required['items'] => { + const items: EuiCollapsibleNavSubItemPropsEnhanced[] = [ + { + renderItem: () => ( + + ), + }, + ]; + + if (spaceBefore) { + items.unshift({ + renderItem: () => , + }); + } + + return items; +}; + +const getEuiProps = ( + _navNode: ChromeProjectNavigationNode, + deps: { navigateToUrl: NavigateToUrlFn; - openPanel: PanelContext['open']; closePanel: PanelContext['close']; - isSideNavCollapsed: boolean; treeDepth: number; - itemsAccordionState: AccordionItemsState; + getIsCollapsed: (path: string) => boolean; activeNodes: ChromeProjectNavigationNode[][]; } ): { - items: Array; - isVisible: boolean; -} => { + navNode: ChromeProjectNavigationNode; + subItems: EuiCollapsibleNavItemProps['items']; + isSelected: boolean; + isItem: boolean; + dataTestSubj: string; + spaceBefore?: EuiThemeSize | null; +} & Pick => { + const { navigateToUrl, closePanel, treeDepth, getIsCollapsed, activeNodes } = deps; const { navNode, isItem, hasChildren, hasLink } = serializeNavNode(_navNode); - const { - id, - path, - href, - renderAs, - onClick: customOnClick, - isCollapsible = DEFAULT_IS_COLLAPSIBLE, - } = navNode; - const isAccordion = isAccordionNode(navNode); + const { path, href, onClick: customOnClick, isCollapsible = DEFAULT_IS_COLLAPSIBLE } = navNode; + const isAccordion = isAccordionNode(navNode); // If the node is an accordion and it is not collapsible, we only want to mark it as active // if it is the highest match in the URL, not if one of its children is also active. const onlyIfHighestMatch = isAccordion && !isCollapsible; const isActive = isActiveFromUrl(navNode.path, activeNodes, onlyIfHighestMatch); const isExternal = Boolean(href) && !navNode.isElasticInternalLink && isAbsoluteLink(href!); - const isAccordionExpanded = - (itemsAccordionState[path]?.isCollapsed ?? DEFAULT_IS_COLLAPSED) === false; - let isSelected = isActive; + const isAccordionExpanded = !getIsCollapsed(path); + let isSelected = isActive; if (isAccordion && isAccordionExpanded) { // For accordions that are collapsible, we don't want to mark the parent button as selected // when it is expanded. If the accordion is **not** collapsible then we do. @@ -223,56 +220,12 @@ const nodeToEuiCollapsibleNavProps = ( spaceBefore = DEFAULT_SPACE_BETWEEN_LEVEL_1_GROUPS; } - if (renderAs === 'panelOpener') { - const items: EuiCollapsibleNavSubItemPropsEnhanced[] = [ - { - renderItem: () => ( - - ), - }, - ]; - if (spaceBefore) { - items.unshift({ - renderItem: () => , - }); - } - return { items, isVisible: true }; - } - - const onClick = (e: React.MouseEvent) => { - if (customOnClick) { - customOnClick(e); - return; - } - - // Do not navigate if it is a collapsible accordion, link will be used in the breadcrumb - if (isAccordion && isCollapsible) return; - - if (href !== undefined) { - e.preventDefault(); - navigateToUrl(href); - closePanel(); - return; - } - }; - const subItems: EuiCollapsibleNavItemProps['items'] | undefined = isItem ? undefined : navNode.children ?.map((child) => - nodeToEuiCollapsibleNavProps(child, { - navigateToUrl, - openPanel, - closePanel, - isSideNavCollapsed, - treeDepth: treeDepth + 1, - itemsAccordionState, - activeNodes, - }) + // Recursively convert the children to EuiCollapsibleNavSubItemProps + nodeToEuiCollapsibleNavProps(child, { ...deps, treeDepth: treeDepth + 1 }) ) .filter(({ isVisible }) => isVisible) .map((res) => { @@ -299,25 +252,81 @@ const nodeToEuiCollapsibleNavProps = ( } : undefined; - if (renderAs === 'block' && treeDepth > 0 && subItems) { - // Render as a group block (bold title + list of links underneath) + const onClick = (e: React.MouseEvent) => { + if (customOnClick) { + customOnClick(e); + return; + } + + // Do not navigate if it is a collapsible accordion, if there is a "link" defined it + // will be used in the breadcrumb navigation. + if (isAccordion && isCollapsible) return; + + if (href !== undefined) { + e.preventDefault(); + navigateToUrl(href); + closePanel(); + return; + } + }; + + return { + navNode, + subItems, + isSelected, + isItem, + spaceBefore, + dataTestSubj, + linkProps, + onClick, + }; +}; + +// Generate the EuiCollapsible props for the root component (EuiCollapsibleNavItem) and its +// "items" props (recursively). Both are compatible with the exception of `renderItem` which +// can only be used for sub items (not top level). +function nodeToEuiCollapsibleNavProps( + _navNode: ChromeProjectNavigationNode, + deps: { + navigateToUrl: NavigateToUrlFn; + closePanel: PanelContext['close']; + treeDepth: number; + getIsCollapsed: (path: string) => boolean; + activeNodes: ChromeProjectNavigationNode[][]; + } +): { + items: Array; + isVisible: boolean; +} { + const { navNode, subItems, dataTestSubj, isSelected, isItem, spaceBefore, linkProps, onClick } = + getEuiProps(_navNode, deps); + const { id, path, href, renderAs, isCollapsible } = navNode; + + if (navNode.renderItem) { + // Leave the rendering to the consumer return { - items: [...renderGroup(navNode, subItems, { spaceBefore: spaceBefore ?? null })], - isVisible: subItems.length > 0, + items: [{ renderItem: navNode.renderItem }], + isVisible: true, }; } - if (navNode.renderItem) { + if (renderAs === 'panelOpener') { + // Render as a panel opener (button to open a panel as a second navigation) return { - items: [ - { - renderItem: navNode.renderItem, - }, - ], + items: [...renderPanelOpener(navNode, deps)], isVisible: true, }; } + if (renderAs === 'block' && deps.treeDepth > 0 && subItems) { + // Render as a group block (bold title + list of links underneath) + return { + items: [...renderGroup(navNode, subItems, { spaceBefore: spaceBefore ?? null })], + isVisible: subItems.length > 0, + }; + } + + // Render as a link or an accordion const items: Array = [ { id, @@ -327,12 +336,12 @@ const nodeToEuiCollapsibleNavProps = ( icon: navNode.icon, title: navNode.title, ['data-test-subj']: dataTestSubj, - iconProps: { size: treeDepth === 0 ? 'm' : 's' }, + iconProps: { size: deps.treeDepth === 0 ? 'm' : 's' }, // Render as an accordion or a link (handled by EUI) depending if // "items" is undefined or not. If it is undefined --> a link, otherwise an // accordion is rendered. - ...(subItems ? { items: subItems } : { href, linkProps }), + ...(subItems ? { items: subItems, isCollapsible } : { href, linkProps }), }, ]; @@ -346,7 +355,7 @@ const nodeToEuiCollapsibleNavProps = ( } return { items, isVisible }; -}; +} const className = css` .euiAccordion__childWrapper { @@ -354,204 +363,46 @@ const className = css` } `; -interface AccordionItemsState { - [navNodeId: string]: { - isCollapsible: boolean; - isCollapsed: boolean; - // We want to auto expand the group automatically if the node is active (URL match) - // but once the user manually expand a group we don't want to close it afterward automatically. - doCollapseFromActiveState: boolean; - }; -} - interface Props { navNode: ChromeProjectNavigationNode; } export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) => { const { activeNodes } = useNavigation(); - const { navigateToUrl, isSideNavCollapsed } = useServices(); + const { navigateToUrl } = useServices(); + const [items, setItems] = useState(); const { navNode } = useMemo( () => serializeNavNode({ - renderAs: 'accordion', // Top level nodes are always rendered as accordion + renderAs: _navNode.children ? 'accordion' : 'item', // Top level nodes are either item or accordion ..._navNode, }), [_navNode] ); - const { open: openPanel, close: closePanel } = usePanel(); + const { close: closePanel } = usePanel(); - const navNodesById = useMemo(() => { - const byId = { - [navNode.path]: navNode, - }; + const { getIsCollapsed, getAccordionProps } = useAccordionState({ navNode }); - const parse = (navNodes?: ChromeProjectNavigationNode[]) => { - if (!navNodes) return; - navNodes.forEach((childNode) => { - byId[childNode.path] = childNode; - parse(childNode.children); - }); - }; - parse(navNode.children); - - return byId; - }, [navNode]); - - const [itemsAccordionState, setItemsAccordionState] = useState(() => { - return Object.entries(navNodesById).reduce((acc, [_id, node]) => { - if (isAccordionNode(node)) { - let isCollapsed = DEFAULT_IS_COLLAPSED; - let doCollapseFromActiveState = true; - - if (node.defaultIsCollapsed !== undefined) { - isCollapsed = node.defaultIsCollapsed; - doCollapseFromActiveState = false; - } - - acc[_id] = { - isCollapsed, - isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, - doCollapseFromActiveState, - }; - } - - return acc; - }, {}); - }); - - const [subItems, setSubItems] = useState(); - - const toggleAccordion = useCallback((id: string) => { - setItemsAccordionState((prev) => { - const prevState = prev[id]; - const prevValue = prevState?.isCollapsed ?? DEFAULT_IS_COLLAPSED; - const { isCollapsible } = prevState; - return { - ...prev, - [id]: { - ...prev[id], - isCollapsed: !prevValue, - doCollapseFromActiveState: isCollapsible - ? // if the accordion is collapsible & the user has interacted with the accordion - // we don't want to auto-close it when URL changes to not interfere with the user's choice - false - : // if the accordion is **not** collapsible we do want to auto-close it when the URL changes - prevState.doCollapseFromActiveState, - }, - }; - }); - }, []); - - const getAccordionProps = useCallback( - ( - id: string, - _accordionProps?: Partial - ): Partial | undefined => { - const isCollapsed = itemsAccordionState[id]?.isCollapsed; - const isCollapsible = itemsAccordionState[id]?.isCollapsible; - - if (isCollapsed === undefined) return _accordionProps; // No state set yet - - let forceState: EuiAccordionProps['forceState'] = isCollapsed ? 'closed' : 'open'; - if (!isCollapsible) forceState = 'open'; // Allways open if the accordion is not collapsible - - const arrowProps: EuiAccordionProps['arrowProps'] = { - css: isCollapsible ? undefined : { display: 'none' }, - 'data-test-subj': classNames(`accordionArrow`, `accordionArrow-${id}`), - }; - - const updated: Partial = { - ..._accordionProps, - arrowProps, - isCollapsible, - forceState, - onToggle: isCollapsible - ? () => { - toggleAccordion(id); - } - : undefined, - }; - - return updated; - }, - [itemsAccordionState, toggleAccordion] - ); - - const { items, isVisible } = useMemo(() => { + const { + items: [props], + isVisible, + } = useMemo(() => { return nodeToEuiCollapsibleNavProps(navNode, { navigateToUrl, - openPanel, closePanel, - isSideNavCollapsed, treeDepth: 0, - itemsAccordionState, + getIsCollapsed, activeNodes, }); - }, [ - navNode, - navigateToUrl, - openPanel, - closePanel, - isSideNavCollapsed, - itemsAccordionState, - activeNodes, - ]); - - const [props] = items; - const { items: accordionItems } = props; - - if (!isEuiCollapsibleNavItemProps(props)) { - throw new Error(`Invalid EuiCollapsibleNavItem props for node ${props.id}`); - } + }, [navNode, navigateToUrl, closePanel, getIsCollapsed, activeNodes]); - /** - * Effect to set the internal state of each of the accordions (isCollapsed) based on the - * "isActive" state of the navNode or if its path matches the URL location - */ - useEffect(() => { - setItemsAccordionState((prev) => { - return Object.entries(navNodesById).reduce( - (acc, [_id, node]) => { - const prevState = prev[_id]; - - if ( - isAccordionNode(node) && - (!prevState || prevState.doCollapseFromActiveState === true) - ) { - let nextIsActive = false; - let doCollapseFromActiveState = true; - - if (!prevState && node.defaultIsCollapsed !== undefined) { - nextIsActive = !node.defaultIsCollapsed; - doCollapseFromActiveState = false; - } else { - if (prevState?.doCollapseFromActiveState !== false) { - nextIsActive = isActiveFromUrl(node.path, activeNodes); - } else if (nextIsActive === undefined) { - nextIsActive = !DEFAULT_IS_COLLAPSED; - } - } - - acc[_id] = { - ...prevState, - isCollapsed: !nextIsActive, - isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, - doCollapseFromActiveState, - }; - } - return acc; - }, - { ...prev } - ); - }); - }, [navNodesById, activeNodes]); + const { items: topLevelItems } = props; - useEffect(() => { - // Serializer to add recursively the accordionProps to each of the items - // that will control its "open"/"closed" state + handler to toggle the state. - const serializeAccordionItems = ( + // Serializer to add recursively the accordionProps to each of the items + // that will control its "open"/"closed" state + handler to toggle the state. + const serializeAccordionItems = useCallback( + ( _items?: EuiCollapsibleNavSubItemPropsEnhanced[] ): EuiCollapsibleNavSubItemProps[] | undefined => { if (!_items) return; @@ -561,12 +412,12 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) return item; } - const itemsSerialized: EuiCollapsibleNavSubItemProps['items'] = serializeAccordionItems( + const subItems: EuiCollapsibleNavSubItemProps['items'] = serializeAccordionItems( item.items ); const accordionProps = - itemsSerialized === undefined + subItems === undefined ? undefined : getAccordionProps(path ?? item.id!, { onClick: item.onClick, @@ -584,10 +435,10 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) ...rest } = item; - const parsed: EuiCollapsibleNavSubItemProps = itemsSerialized + const parsed: EuiCollapsibleNavSubItemProps = subItems ? { ...rest, - items: itemsSerialized, + items: subItems, accordionProps, isCollapsible, } @@ -599,27 +450,35 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) return parsed; }); - }; + }, + [getAccordionProps] + ); - setSubItems(serializeAccordionItems(accordionItems)); - }, [accordionItems, getAccordionProps]); + useEffect(() => { + setItems(serializeAccordionItems(topLevelItems)); + }, [topLevelItems, serializeAccordionItems]); + + if (!isEuiCollapsibleNavItemProps(props)) { + throw new Error(`Invalid EuiCollapsibleNavItem props for node ${props.id}`); + } if (!isVisible) { return null; } - if (!subItems) { + + if (!items) { return ; } + // Item type ExclusiveUnion - accordions should not contain links + const { href, linkProps, ...rest } = props; + return ( ); }); diff --git a/packages/shared-ux/chrome/navigation/src/ui/constants.ts b/packages/shared-ux/chrome/navigation/src/ui/constants.ts new file mode 100644 index 0000000000000..4a6a85bba00ae --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/ui/constants.ts @@ -0,0 +1,13 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import type { EuiThemeSize, RenderAs } from '@kbn/core-chrome-browser'; + +export const DEFAULT_SPACE_BETWEEN_LEVEL_1_GROUPS: EuiThemeSize = 'm'; +export const DEFAULT_IS_COLLAPSED = true; +export const DEFAULT_IS_COLLAPSIBLE = true; +export const DEFAULT_RENDER_AS: RenderAs = 'block'; diff --git a/packages/shared-ux/chrome/navigation/src/ui/hooks/index.ts b/packages/shared-ux/chrome/navigation/src/ui/hooks/index.ts new file mode 100644 index 0000000000000..acfda4ab1bd2e --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/ui/hooks/index.ts @@ -0,0 +1,9 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { useAccordionState, type AccordionItemsState } from './use_accordion_state'; diff --git a/packages/shared-ux/chrome/navigation/src/ui/hooks/use_accordion_state.ts b/packages/shared-ux/chrome/navigation/src/ui/hooks/use_accordion_state.ts new file mode 100644 index 0000000000000..782d93464df15 --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/ui/hooks/use_accordion_state.ts @@ -0,0 +1,181 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useCallback, useMemo, useState, useEffect } from 'react'; +import classNames from 'classnames'; +import { type EuiAccordionProps } from '@elastic/eui'; +import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; + +import { isAccordionNode, isActiveFromUrl } from '../../utils'; +import { DEFAULT_IS_COLLAPSED, DEFAULT_IS_COLLAPSIBLE } from '../constants'; +import { useNavigation } from '../navigation'; + +export interface AccordionItemsState { + [navNodeId: string]: { + isCollapsible: boolean; + isCollapsed: boolean; + // We want to auto expand the group automatically if the node is active (URL match) + // but once the user manually expand a group we don't want to close it afterward automatically. + doCollapseFromActiveState: boolean; + }; +} + +export const useAccordionState = ({ navNode }: { navNode: ChromeProjectNavigationNode }) => { + const { activeNodes } = useNavigation(); + + const navNodesById = useMemo(() => { + const byId = { + [navNode.path]: navNode, + }; + + const parse = (navNodes?: ChromeProjectNavigationNode[]) => { + if (!navNodes) return; + navNodes.forEach((childNode) => { + byId[childNode.path] = childNode; + parse(childNode.children); + }); + }; + parse(navNode.children); + + return byId; + }, [navNode]); + + const [accordionStateById, setAccordionStateById] = useState(() => { + return Object.entries(navNodesById).reduce((acc, [_id, node]) => { + if (isAccordionNode(node)) { + let isCollapsed = DEFAULT_IS_COLLAPSED; + let doCollapseFromActiveState = true; + + if (node.defaultIsCollapsed !== undefined) { + isCollapsed = node.defaultIsCollapsed; + doCollapseFromActiveState = false; + } + + acc[_id] = { + isCollapsed, + isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, + doCollapseFromActiveState, + }; + } + + return acc; + }, {}); + }); + + const toggleAccordion = useCallback((path: string) => { + setAccordionStateById((prev) => { + const prevState = prev[path]; + const prevValue = prevState?.isCollapsed ?? DEFAULT_IS_COLLAPSED; + const { isCollapsible } = prevState; + return { + ...prev, + [path]: { + ...prev[path], + isCollapsed: !prevValue, + doCollapseFromActiveState: isCollapsible + ? // if the accordion is collapsible & the user has interacted with the accordion + // we don't want to auto-close it when URL changes to not interfere with the user's choice + false + : // if the accordion is **not** collapsible we do want to auto-close it when the URL changes + prevState.doCollapseFromActiveState, + }, + }; + }); + }, []); + + const getAccordionProps = useCallback( + ( + path: string, + _accordionProps?: Partial + ): Partial | undefined => { + const isCollapsed = accordionStateById[path]?.isCollapsed; + const isCollapsible = accordionStateById[path]?.isCollapsible; + + if (isCollapsed === undefined) return _accordionProps; // No state set yet + + let forceState: EuiAccordionProps['forceState'] = isCollapsed ? 'closed' : 'open'; + if (!isCollapsible) forceState = 'open'; // Allways open if the accordion is not collapsible + + const arrowProps: EuiAccordionProps['arrowProps'] = { + css: isCollapsible ? undefined : { display: 'none' }, + 'data-test-subj': classNames(`accordionArrow`, `accordionArrow-${path}`), + }; + + const updated: Partial = { + ..._accordionProps, + arrowProps, + isCollapsible, + forceState, + onToggle: isCollapsible + ? () => { + toggleAccordion(path); + } + : undefined, + }; + + return updated; + }, + [accordionStateById, toggleAccordion] + ); + + const getIsCollapsed = useCallback( + (path: string) => { + return accordionStateById[path]?.isCollapsed ?? DEFAULT_IS_COLLAPSED; + }, + [accordionStateById] + ); + + /** + * Effect to set the internal state of each of the accordions (isCollapsed) based on the + * "isActive" state of the navNode or if its path matches the URL location + */ + useEffect(() => { + setAccordionStateById((prev) => { + return Object.entries(navNodesById).reduce( + (acc, [_id, node]) => { + const prevState = prev[_id]; + + if ( + isAccordionNode(node) && + (!prevState || prevState.doCollapseFromActiveState === true) + ) { + let nextIsActive = false; + let doCollapseFromActiveState = true; + + if (!prevState && node.defaultIsCollapsed !== undefined) { + nextIsActive = !node.defaultIsCollapsed; + doCollapseFromActiveState = false; + } else { + if (prevState?.doCollapseFromActiveState !== false) { + nextIsActive = isActiveFromUrl(node.path, activeNodes); + } else if (nextIsActive === undefined) { + nextIsActive = !DEFAULT_IS_COLLAPSED; + } + } + + acc[_id] = { + ...prevState, + isCollapsed: !nextIsActive, + isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, + doCollapseFromActiveState, + }; + } + return acc; + }, + { ...prev } + ); + }); + }, [navNodesById, activeNodes]); + + return { + /** Get the EUI accordion props for the node at a specific path */ + getAccordionProps, + /** Get the isCollapsed state for a node at a specific path */ + getIsCollapsed, + }; +}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/types.ts b/packages/shared-ux/chrome/navigation/src/ui/types.ts index 10b1b7630b20c..ec01773b422db 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/types.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/types.ts @@ -5,53 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { ReactNode } from 'react'; +import { type EuiCollapsibleNavSubItemProps } from '@elastic/eui'; -import type { - AppDeepLinkId, - ChromeProjectNavigationNode, - NodeDefinition, -} from '@kbn/core-chrome-browser'; - -/** - * @public - * - * A navigation node definition with its unique id, title, path in the tree and optional deep link. - * Those are the props that can be passed to the Navigation.Group and Navigation.Item components. - */ -export interface NodeProps< - LinkId extends AppDeepLinkId = AppDeepLinkId, - Id extends string = string, - ChildrenId extends string = Id -> extends Omit, 'children'> { - /** - * Children of the node. For Navigation.Item (only) it allows a function to be set. - * This function will receive the ChromeProjectNavigationNode object - */ - children?: ReactNode; - /** @internal - Prop internally controlled, don't use it. */ - parentNodePath?: string; - /** @internal - Prop internally controlled, don't use it. */ - rootIndex?: number; - /** @internal - Prop internally controlled, don't use it. */ - treeDepth?: number; - /** @internal - Prop internally controlled, don't use it. */ - index?: number; -} - -/** - * @internal - * - * Function to unregister a navigation node from its parent. - */ -export type UnRegisterFunction = () => void; - -/** - * @internal - * - * A function to register a navigation node on its parent. - */ -export type RegisterFunction = ( - navNode: ChromeProjectNavigationNode, - order?: number -) => UnRegisterFunction; +export type EuiCollapsibleNavSubItemPropsEnhanced = EuiCollapsibleNavSubItemProps & { + path?: string; +}; diff --git a/packages/shared-ux/chrome/navigation/src/utils.ts b/packages/shared-ux/chrome/navigation/src/utils.ts index 5b070c55176f0..f63ff518a18d4 100644 --- a/packages/shared-ux/chrome/navigation/src/utils.ts +++ b/packages/shared-ux/chrome/navigation/src/utils.ts @@ -39,3 +39,9 @@ export function isActiveFromUrl( : nodesBranch.some((branch) => isSamePath(branch.path, nodePath)); }, false); } + +export const isAccordionNode = ( + node: Pick +) => + node.renderAs === 'accordion' || + ['defaultIsCollapsed', 'isCollapsible'].some((prop) => node.hasOwnProperty(prop)); diff --git a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts index 24287170b83a6..5c9dc65027b6b 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts @@ -33,7 +33,6 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlCommonNavigation.breadcrumbs.expectExists(); // check side nav links - await svlCommonNavigation.sidenav.expectSectionOpen('observability_project_nav'); await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ deepLinkId: 'observabilityOnboarding', }); diff --git a/x-pack/test_serverless/functional/test_suites/search/navigation.ts b/x-pack/test_serverless/functional/test_suites/search/navigation.ts index 85042af186ebc..554a2e2b63c15 100644 --- a/x-pack/test_serverless/functional/test_suites/search/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/search/navigation.ts @@ -37,7 +37,6 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { // check side nav links await testSubjects.existOrFail(`svlSearchOverviewPage`); - await svlCommonNavigation.sidenav.expectSectionOpen('search_project_nav'); await svlCommonNavigation.sidenav.expectLinkActive({ deepLinkId: 'serverlessElasticsearch', }); From a03f3bce7dfc3a7daac6367954290890d92ac34d Mon Sep 17 00:00:00 2001 From: Ido Cohen <90558359+CohenIdo@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:06:39 +0300 Subject: [PATCH 05/87] [Cloud Security] FTRs for Accessing Pages with Custom Roles (#184622) --- ...enerated_csp_requirements_test_coverage.md | 46 +- .../__auto_generated_csp_test_log.json | 671 +++++++++++++++++- .../latest_findings_transform.ts | 4 +- .../latest_vulnerabilities_transforms.ts | 5 +- .../page_objects/benchmark_page.ts | 59 ++ .../page_objects/findings_page.ts | 5 + .../page_objects/index.ts | 4 + .../page_objects/security_common.ts | 128 ++++ .../pages/benchmark.ts | 79 +++ .../pages/compliance_dashboard.ts | 27 +- .../pages/findings.ts | 29 +- .../pages/findings_grouping.ts | 2 + .../pages/index.ts | 12 +- 13 files changed, 1019 insertions(+), 52 deletions(-) create mode 100644 x-pack/test/cloud_security_posture_functional/page_objects/benchmark_page.ts create mode 100644 x-pack/test/cloud_security_posture_functional/page_objects/security_common.ts create mode 100644 x-pack/test/cloud_security_posture_functional/pages/benchmark.ts diff --git a/x-pack/plugins/cloud_security_posture/common/dev_docs/__auto_generated_csp_requirements_test_coverage.md b/x-pack/plugins/cloud_security_posture/common/dev_docs/__auto_generated_csp_requirements_test_coverage.md index 16c826cbc9dd2..a6fdc6aa618ab 100644 --- a/x-pack/plugins/cloud_security_posture/common/dev_docs/__auto_generated_csp_requirements_test_coverage.md +++ b/x-pack/plugins/cloud_security_posture/common/dev_docs/__auto_generated_csp_requirements_test_coverage.md @@ -7,7 +7,7 @@ You can also check out the dedicated app view, which enables easier search and f ## Directory: x-pack/plugins/cloud_security_posture -**Total Tests:** 444 | **Skipped:** 5 (1.13%) | **Todo:** 0 (0.00%) +**Total Tests:** 458 | **Skipped:** 5 (1.09%) | **Todo:** 0 (0.00%) ![](https://img.shields.io/badge/UT-brightgreen) ![](https://img.shields.io/badge/HAS-SKIP-yellow) @@ -69,7 +69,6 @@ You can also check out the dedicated app view, which enables easier search and f | [useNavigateFindings](x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts) | describe | | | | [creates a URL to findings page with correct path, filter and dataViewId](x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts) | it | | | | [creates a URL to findings page with correct path and negated filter](x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts) | it | | | -| [creates a URL to findings resource page with correct path and filter](x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts) | it | | | | [creates a URL to vulnerabilities page with correct path, filter and dataViewId](x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts) | it | | | | [useUrlQuery](x-pack/plugins/cloud_security_posture/public/common/hooks/use_url_query.test.ts) | describe | | | | [uses default query when no query is provided](x-pack/plugins/cloud_security_posture/public/common/hooks/use_url_query.test.ts) | it | | | @@ -266,6 +265,14 @@ You can also check out the dedicated app view, which enables easier search and f | [Should return undefined when datastream is undefined](x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts) | it | | | | [Should return undefined when stream is undefined](x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts) | it | | | | [Should return undefined when stream.var is invalid](x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts) | it | | | +| [NoFindingsStates](x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx) | describe | | | +| [should show the indexing notification when CSPM is not installed and KSPM is indexing](x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx) | it | | | +| [should show the indexing notification when KSPM is not installed and CSPM is indexing](x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx) | it | | | +| [should show the indexing timout notification when CSPM is status is index-timeout](x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx) | it | | | +| [should show the indexing timout notification when KSPM is status is index-timeout](x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx) | it | | | +| [should show the unprivileged notification when CSPM is status is index-timeout](x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx) | it | | | +| [should show the unprivileged notification when KSPM is status is index-timeout](x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx) | it | | | +| [should show the not-installed notification when CSPM and KSPM status is not-installed](x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx) | it | | | | [](x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks_table.test.tsx) | describe | | | | [renders cis integration name](x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks_table.test.tsx) | it | | | | [renders benchmark version](x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks_table.test.tsx) | it | | | @@ -335,6 +342,13 @@ You can also check out the dedicated app view, which enables easier search and f | [](x-pack/plugins/cloud_security_posture/public/pages/rules/rules.test.tsx) | describe | | | | [calls Benchmark API](x-pack/plugins/cloud_security_posture/public/pages/rules/rules.test.tsx) | it | | | | [Display success state when result request is resolved](x-pack/plugins/cloud_security_posture/public/pages/rules/rules.test.tsx) | it | | | +| [use_change_csp_rule_state](x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx) | describe | | | +| [should call http.post with the correct parameters](x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx) | it | | | +| [should cancel queries and update query data onMutate](x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx) | it | | | +| [should invalidate queries onSettled](x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx) | it | | | +| [should restore previous query data onError](x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx) | it | | | +| [creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState](x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx) | it | | | +| [creates the new cache with rules in a unmute state](x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx) | it | | | | [](x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx) | describe | | | | [Header Info](x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx) | describe | | | | [displays text details flyout header info](x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx) | it | | | @@ -464,9 +478,9 @@ You can also check out the dedicated app view, which enables easier search and f ## Directory: x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture -**Total Tests:** 37 | **Skipped:** 4 (10.81%) | **Todo:** 0 (0.00%) +**Total Tests:** 37 | **Skipped:** 0 (0.00%) | **Todo:** 0 (0.00%) -![](https://img.shields.io/badge/FTR-blue) ![](https://img.shields.io/badge/SERVERLESS-pink) ![](https://img.shields.io/badge/API-INTEGRATION-purple) ![](https://img.shields.io/badge/HAS-SKIP-yellow) +![](https://img.shields.io/badge/FTR-blue) ![](https://img.shields.io/badge/SERVERLESS-pink) ![](https://img.shields.io/badge/API-INTEGRATION-purple)
Test Details @@ -490,10 +504,10 @@ You can also check out the dedicated app view, which enables easier search and f | [Should return 200 status code and paginate rules with a limit of PerPage](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/find_csp_benchmark_rule.ts) | it | | | | [cloud_security_posture](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/index.ts) | describe | | | | [GET /internal/cloud_security_posture/status](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | describe | | | -| [STATUS = INDEXED TEST](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | describe | ![](https://img.shields.io/badge/skipped-yellow) | | -| [Return kspm status indexed when logs-cloud_security_posture.findings_latest-default contains new kspm documents](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | it | ![](https://img.shields.io/badge/skipped-yellow) | | -| [Return cspm status indexed when logs-cloud_security_posture.findings_latest-default contains new cspm documents](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | it | ![](https://img.shields.io/badge/skipped-yellow) | | -| [Return vuln status indexed when logs-cloud_security_posture.vulnerabilities_latest-default contains new documents](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | it | ![](https://img.shields.io/badge/skipped-yellow) | | +| [STATUS = INDEXED TEST](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | describe | | | +| [Return kspm status indexed when logs-cloud_security_posture.findings_latest-default contains new kspm documents](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | it | | | +| [Return cspm status indexed when logs-cloud_security_posture.findings_latest-default contains new cspm documents](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | it | | | +| [Return vuln status indexed when logs-cloud_security_posture.vulnerabilities_latest-default contains new documents](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts) | it | | | | [GET /internal/cloud_security_posture/status](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts) | describe | | | | [STATUS = INDEXING TEST](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts) | describe | | | | [Return kspm status indexing when logs-cloud_security_posture.findings_latest-default doesn](x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts) | it | | | @@ -654,15 +668,21 @@ You can also check out the dedicated app view, which enables easier search and f ## Directory: x-pack/test/cloud_security_posture_functional -**Total Tests:** 190 | **Skipped:** 37 (19.47%) | **Todo:** 2 (1.05%) +**Total Tests:** 202 | **Skipped:** 41 (20.30%) | **Todo:** 3 (1.49%) -![](https://img.shields.io/badge/FTR-blue) ![](https://img.shields.io/badge/HAS-TODO-green) ![](https://img.shields.io/badge/HAS-SKIP-yellow) +![](https://img.shields.io/badge/FTR-blue) ![](https://img.shields.io/badge/HAS-SKIP-yellow) ![](https://img.shields.io/badge/HAS-TODO-green)
Test Details | Test Label | Type | Skipped | Todo | |------------|------|---------|------| +| [Access with custom roles](x-pack/test/cloud_security_posture_functional/pages/benchmark.ts) | describe | | | +| [Access with valid user role](x-pack/test/cloud_security_posture_functional/pages/benchmark.ts) | it | ![](https://img.shields.io/badge/skipped-yellow) | | +| [Access with invalid user role](x-pack/test/cloud_security_posture_functional/pages/benchmark.ts) | it | ![](https://img.shields.io/badge/skipped-yellow) | | +| [Access with custom roles - rule page](x-pack/test/cloud_security_posture_functional/pages/benchmark.ts) | describe | | | +| [Access with valid user role](x-pack/test/cloud_security_posture_functional/pages/benchmark.ts) | it | | | +| [Access with invalid user role](x-pack/test/cloud_security_posture_functional/pages/benchmark.ts) | it | ![](https://img.shields.io/badge/skipped-yellow) | | | [Test adding Cloud Security Posture Integrations CNVM](x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts) | describe | | | | [CNVM AWS](x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts) | describe | | | | [Hyperlink on PostInstallation Modal should have the correct URL](x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts) | it | | | @@ -748,6 +768,9 @@ You can also check out the dedicated app view, which enables easier search and f | [displays accurate summary compliance score](x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts) | it | | | | [TODO - Cloud Dashboard](x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts) | describe | | ![](https://img.shields.io/badge/todo-green) | | [todo - displays accurate summary compliance score](x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts) | it | | ![](https://img.shields.io/badge/todo-green) | +| [Access with custom roles](x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts) | describe | | | +| [Access with valid user role](x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts) | it | | | +| [todo - Access with invalid user role](x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts) | it | ![](https://img.shields.io/badge/skipped-yellow) | ![](https://img.shields.io/badge/todo-green) | | [Findings Page - Alerts](x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts) | describe | | | | [Create detection rule](x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts) | describe | ![](https://img.shields.io/badge/skipped-yellow) | | | [Creates a detection rule from the Take Action button and navigates to rule page](x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts) | it | ![](https://img.shields.io/badge/skipped-yellow) | | @@ -796,6 +819,9 @@ You can also check out the dedicated app view, which enables easier search and f | [Reset fields to default](x-pack/test/cloud_security_posture_functional/pages/findings.ts) | it | | | | [Findings Page - support muting rules](x-pack/test/cloud_security_posture_functional/pages/findings.ts) | describe | | | | [verify only enabled rules appears](x-pack/test/cloud_security_posture_functional/pages/findings.ts) | it | | | +| [Access with custom roles](x-pack/test/cloud_security_posture_functional/pages/findings.ts) | describe | | | +| [Access with valid user role](x-pack/test/cloud_security_posture_functional/pages/findings.ts) | it | | | +| [Access with invalid user role](x-pack/test/cloud_security_posture_functional/pages/findings.ts) | it | | | | [Cloud Security Posture](x-pack/test/cloud_security_posture_functional/pages/index.ts) | describe | | | | [Cloud Posture Rules Page](x-pack/test/cloud_security_posture_functional/pages/rules.ts) | describe | ![](https://img.shields.io/badge/skipped-yellow) | | | [Rules Page - Rules Counters](x-pack/test/cloud_security_posture_functional/pages/rules.ts) | describe | ![](https://img.shields.io/badge/skipped-yellow) | | diff --git a/x-pack/plugins/cloud_security_posture/common/scripts/__auto_generated_csp_test_log.json b/x-pack/plugins/cloud_security_posture/common/scripts/__auto_generated_csp_test_log.json index 98a7c6629ee7e..8c177cd46e713 100644 --- a/x-pack/plugins/cloud_security_posture/common/scripts/__auto_generated_csp_test_log.json +++ b/x-pack/plugins/cloud_security_posture/common/scripts/__auto_generated_csp_test_log.json @@ -1148,7 +1148,6 @@ "describe('useNavigateFindings')", " it('creates a URL to findings page with correct path, filter and dataViewId')", " it('creates a URL to findings page with correct path and negated filter')", - " it('creates a URL to findings resource page with correct path and filter')", " it('creates a URL to vulnerabilities page with correct path, filter and dataViewId')" ], "testSuits": [ @@ -1182,16 +1181,6 @@ "isSkipped": false, "isTodo": false }, - { - "id": "creates-a-url-to-findings-resource-page-with-correct-path-and-filter", - "rawLine": " it('creates a URL to findings resource page with correct path and filter', () => {", - "line": " it('creates a URL to findings resource page with correct path and filter')", - "label": "creates a URL to findings resource page with correct path and filter", - "indent": 2, - "type": "it", - "isSkipped": false, - "isTodo": false - }, { "id": "creates-a-url-to-vulnerabilities-page-with-correct-path,-filter-and-dataviewid", "rawLine": " it('creates a URL to vulnerabilities page with correct path, filter and dataViewId', () => {", @@ -1234,16 +1223,6 @@ "isSkipped": false, "isTodo": false }, - { - "id": "creates-a-url-to-findings-resource-page-with-correct-path-and-filter", - "rawLine": " it('creates a URL to findings resource page with correct path and filter', () => {", - "line": " it('creates a URL to findings resource page with correct path and filter')", - "label": "creates a URL to findings resource page with correct path and filter", - "indent": 2, - "type": "it", - "isSkipped": false, - "isTodo": false - }, { "id": "creates-a-url-to-vulnerabilities-page-with-correct-path,-filter-and-dataviewid", "rawLine": " it('creates a URL to vulnerabilities page with correct path, filter and dataViewId', () => {", @@ -5695,6 +5674,190 @@ } ] }, + { + "filePath": "x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx", + "fileName": "no_findings_states.test.tsx", + "directory": "x-pack/plugins/cloud_security_posture", + "tags": [ + "UT" + ], + "lines": [ + "describe('NoFindingsStates')", + " it('should show the indexing notification when CSPM is not installed and KSPM is indexing')", + " it('should show the indexing notification when KSPM is not installed and CSPM is indexing')", + " it('should show the indexing timout notification when CSPM is status is index-timeout')", + " it('should show the indexing timout notification when KSPM is status is index-timeout')", + " it('should show the unprivileged notification when CSPM is status is index-timeout')", + " it('should show the unprivileged notification when KSPM is status is index-timeout')", + " it('should show the not-installed notification when CSPM and KSPM status is not-installed')" + ], + "testSuits": [ + { + "id": "nofindingsstates", + "rawLine": "describe('NoFindingsStates', () => {", + "line": "describe('NoFindingsStates')", + "label": "NoFindingsStates", + "indent": 0, + "type": "describe", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-indexing-notification-when-cspm-is-not-installed-and-kspm-is-indexing", + "rawLine": " it('should show the indexing notification when CSPM is not installed and KSPM is indexing', async () => {", + "line": " it('should show the indexing notification when CSPM is not installed and KSPM is indexing')", + "label": "should show the indexing notification when CSPM is not installed and KSPM is indexing", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-indexing-notification-when-kspm-is-not-installed-and-cspm-is-indexing", + "rawLine": " it('should show the indexing notification when KSPM is not installed and CSPM is indexing', async () => {", + "line": " it('should show the indexing notification when KSPM is not installed and CSPM is indexing')", + "label": "should show the indexing notification when KSPM is not installed and CSPM is indexing", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-indexing-timout-notification-when-cspm-is-status-is-index-timeout", + "rawLine": " it('should show the indexing timout notification when CSPM is status is index-timeout', async () => {", + "line": " it('should show the indexing timout notification when CSPM is status is index-timeout')", + "label": "should show the indexing timout notification when CSPM is status is index-timeout", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-indexing-timout-notification-when-kspm-is-status-is-index-timeout", + "rawLine": " it('should show the indexing timout notification when KSPM is status is index-timeout', async () => {", + "line": " it('should show the indexing timout notification when KSPM is status is index-timeout')", + "label": "should show the indexing timout notification when KSPM is status is index-timeout", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-unprivileged-notification-when-cspm-is-status-is-index-timeout", + "rawLine": " it('should show the unprivileged notification when CSPM is status is index-timeout', async () => {", + "line": " it('should show the unprivileged notification when CSPM is status is index-timeout')", + "label": "should show the unprivileged notification when CSPM is status is index-timeout", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-unprivileged-notification-when-kspm-is-status-is-index-timeout", + "rawLine": " it('should show the unprivileged notification when KSPM is status is index-timeout', async () => {", + "line": " it('should show the unprivileged notification when KSPM is status is index-timeout')", + "label": "should show the unprivileged notification when KSPM is status is index-timeout", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-not-installed-notification-when-cspm-and-kspm-status-is-not-installed", + "rawLine": " it('should show the not-installed notification when CSPM and KSPM status is not-installed', async () => {", + "line": " it('should show the not-installed notification when CSPM and KSPM status is not-installed')", + "label": "should show the not-installed notification when CSPM and KSPM status is not-installed", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + } + ], + "tree": [ + { + "id": "nofindingsstates", + "rawLine": "describe('NoFindingsStates', () => {", + "line": "describe('NoFindingsStates')", + "label": "NoFindingsStates", + "indent": 0, + "type": "describe", + "isSkipped": false, + "isTodo": false, + "children": [ + { + "id": "should-show-the-indexing-notification-when-cspm-is-not-installed-and-kspm-is-indexing", + "rawLine": " it('should show the indexing notification when CSPM is not installed and KSPM is indexing', async () => {", + "line": " it('should show the indexing notification when CSPM is not installed and KSPM is indexing')", + "label": "should show the indexing notification when CSPM is not installed and KSPM is indexing", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-indexing-notification-when-kspm-is-not-installed-and-cspm-is-indexing", + "rawLine": " it('should show the indexing notification when KSPM is not installed and CSPM is indexing', async () => {", + "line": " it('should show the indexing notification when KSPM is not installed and CSPM is indexing')", + "label": "should show the indexing notification when KSPM is not installed and CSPM is indexing", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-indexing-timout-notification-when-cspm-is-status-is-index-timeout", + "rawLine": " it('should show the indexing timout notification when CSPM is status is index-timeout', async () => {", + "line": " it('should show the indexing timout notification when CSPM is status is index-timeout')", + "label": "should show the indexing timout notification when CSPM is status is index-timeout", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-indexing-timout-notification-when-kspm-is-status-is-index-timeout", + "rawLine": " it('should show the indexing timout notification when KSPM is status is index-timeout', async () => {", + "line": " it('should show the indexing timout notification when KSPM is status is index-timeout')", + "label": "should show the indexing timout notification when KSPM is status is index-timeout", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-unprivileged-notification-when-cspm-is-status-is-index-timeout", + "rawLine": " it('should show the unprivileged notification when CSPM is status is index-timeout', async () => {", + "line": " it('should show the unprivileged notification when CSPM is status is index-timeout')", + "label": "should show the unprivileged notification when CSPM is status is index-timeout", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-unprivileged-notification-when-kspm-is-status-is-index-timeout", + "rawLine": " it('should show the unprivileged notification when KSPM is status is index-timeout', async () => {", + "line": " it('should show the unprivileged notification when KSPM is status is index-timeout')", + "label": "should show the unprivileged notification when KSPM is status is index-timeout", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-show-the-not-installed-notification-when-cspm-and-kspm-status-is-not-installed", + "rawLine": " it('should show the not-installed notification when CSPM and KSPM status is not-installed', async () => {", + "line": " it('should show the not-installed notification when CSPM and KSPM status is not-installed')", + "label": "should show the not-installed notification when CSPM and KSPM status is not-installed", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + } + ] + } + ] + }, { "filePath": "x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks_table.test.tsx", "fileName": "benchmarks_table.test.tsx", @@ -7330,6 +7493,169 @@ } ] }, + { + "filePath": "x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx", + "fileName": "use_change_csp_rule_state.test.tsx", + "directory": "x-pack/plugins/cloud_security_posture", + "tags": [ + "UT" + ], + "lines": [ + "describe('use_change_csp_rule_state')", + " it('should call http.post with the correct parameters')", + " it('should cancel queries and update query data onMutate')", + " it('should invalidate queries onSettled')", + " it('should restore previous query data onError')", + " it('creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState')", + " it('creates the new cache with rules in a unmute state')" + ], + "testSuits": [ + { + "id": "use_change_csp_rule_state", + "rawLine": "describe('use_change_csp_rule_state', () => {", + "line": "describe('use_change_csp_rule_state')", + "label": "use_change_csp_rule_state", + "indent": 0, + "type": "describe", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-call-http.post-with-the-correct-parameters", + "rawLine": " it('should call http.post with the correct parameters', async () => {", + "line": " it('should call http.post with the correct parameters')", + "label": "should call http.post with the correct parameters", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-cancel-queries-and-update-query-data-onmutate", + "rawLine": " it('should cancel queries and update query data onMutate', async () => {", + "line": " it('should cancel queries and update query data onMutate')", + "label": "should cancel queries and update query data onMutate", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-invalidate-queries-onsettled", + "rawLine": " it('should invalidate queries onSettled', async () => {", + "line": " it('should invalidate queries onSettled')", + "label": "should invalidate queries onSettled", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-restore-previous-query-data-onerror", + "rawLine": " it('should restore previous query data onError', async () => {", + "line": " it('should restore previous query data onError')", + "label": "should restore previous query data onError", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "creates-the-new-set-of-cache-rules-in-a-muted-state-when-calling-createruleswithupdatedstate", + "rawLine": " it('creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState', async () => {", + "line": " it('creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState')", + "label": "creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "creates-the-new-cache-with-rules-in-a-unmute-state", + "rawLine": " it('creates the new cache with rules in a unmute state', async () => {", + "line": " it('creates the new cache with rules in a unmute state')", + "label": "creates the new cache with rules in a unmute state", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + } + ], + "tree": [ + { + "id": "use_change_csp_rule_state", + "rawLine": "describe('use_change_csp_rule_state', () => {", + "line": "describe('use_change_csp_rule_state')", + "label": "use_change_csp_rule_state", + "indent": 0, + "type": "describe", + "isSkipped": false, + "isTodo": false, + "children": [ + { + "id": "should-call-http.post-with-the-correct-parameters", + "rawLine": " it('should call http.post with the correct parameters', async () => {", + "line": " it('should call http.post with the correct parameters')", + "label": "should call http.post with the correct parameters", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-cancel-queries-and-update-query-data-onmutate", + "rawLine": " it('should cancel queries and update query data onMutate', async () => {", + "line": " it('should cancel queries and update query data onMutate')", + "label": "should cancel queries and update query data onMutate", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-invalidate-queries-onsettled", + "rawLine": " it('should invalidate queries onSettled', async () => {", + "line": " it('should invalidate queries onSettled')", + "label": "should invalidate queries onSettled", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "should-restore-previous-query-data-onerror", + "rawLine": " it('should restore previous query data onError', async () => {", + "line": " it('should restore previous query data onError')", + "label": "should restore previous query data onError", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "creates-the-new-set-of-cache-rules-in-a-muted-state-when-calling-createruleswithupdatedstate", + "rawLine": " it('creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState', async () => {", + "line": " it('creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState')", + "label": "creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "creates-the-new-cache-with-rules-in-a-unmute-state", + "rawLine": " it('creates the new cache with rules in a unmute state', async () => {", + "line": " it('creates the new cache with rules in a unmute state')", + "label": "creates the new cache with rules in a unmute state", + "indent": 2, + "type": "it", + "isSkipped": false, + "isTodo": false + } + ] + } + ] + }, { "filePath": "x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx", "fileName": "vulnerability_finding_flyout.test.tsx", @@ -10683,12 +11009,11 @@ "tags": [ "FTR", "SERVERLESS", - "API INTEGRATION", - "HAS SKIP" + "API INTEGRATION" ], "lines": [ " describe('GET /internal/cloud_security_posture/status')", - " describe.skip('STATUS = INDEXED TEST')", + " describe('STATUS = INDEXED TEST')", " it(`Return kspm status indexed when logs-cloud_security_posture.findings_latest-default contains new kspm documents`)", " it(`Return cspm status indexed when logs-cloud_security_posture.findings_latest-default contains new cspm documents`)", " it(`Return vuln status indexed when logs-cloud_security_posture.vulnerabilities_latest-default contains new documents`)" @@ -10706,12 +11031,12 @@ }, { "id": "status-=-indexed-test", - "rawLine": " describe.skip('STATUS = INDEXED TEST', () => {", - "line": " describe.skip('STATUS = INDEXED TEST')", + "rawLine": " describe('STATUS = INDEXED TEST', () => {", + "line": " describe('STATUS = INDEXED TEST')", "label": "STATUS = INDEXED TEST", "indent": 4, "type": "describe", - "isSkipped": true, + "isSkipped": false, "isTodo": false }, { @@ -10758,12 +11083,12 @@ "children": [ { "id": "status-=-indexed-test", - "rawLine": " describe.skip('STATUS = INDEXED TEST', () => {", - "line": " describe.skip('STATUS = INDEXED TEST')", + "rawLine": " describe('STATUS = INDEXED TEST', () => {", + "line": " describe('STATUS = INDEXED TEST')", "label": "STATUS = INDEXED TEST", "indent": 4, "type": "describe", - "isSkipped": true, + "isSkipped": false, "isTodo": false, "children": [ { @@ -10773,7 +11098,7 @@ "label": "Return kspm status indexed when logs-cloud_security_posture.findings_latest-default contains new kspm documents", "indent": 6, "type": "it", - "isSkipped": true, + "isSkipped": false, "isTodo": false }, { @@ -10783,7 +11108,7 @@ "label": "Return cspm status indexed when logs-cloud_security_posture.findings_latest-default contains new cspm documents", "indent": 6, "type": "it", - "isSkipped": true, + "isSkipped": false, "isTodo": false }, { @@ -10793,7 +11118,7 @@ "label": "Return vuln status indexed when logs-cloud_security_posture.vulnerabilities_latest-default contains new documents", "indent": 6, "type": "it", - "isSkipped": true, + "isSkipped": false, "isTodo": false } ] @@ -13678,6 +14003,151 @@ } ] }, + { + "filePath": "x-pack/test/cloud_security_posture_functional/pages/benchmark.ts", + "fileName": "benchmark.ts", + "directory": "x-pack/test/cloud_security_posture_functional", + "tags": [ + "FTR", + "HAS SKIP" + ], + "lines": [ + " describe('Access with custom roles')", + " it.skip('Access with valid user role')", + " it.skip('Access with invalid user role')", + " describe('Access with custom roles - rule page')", + " it('Access with valid user role')", + " it.skip('Access with invalid user role')" + ], + "testSuits": [ + { + "id": "access-with-custom-roles", + "rawLine": " describe('Access with custom roles', async () => {", + "line": " describe('Access with custom roles')", + "label": "Access with custom roles", + "indent": 2, + "type": "describe", + "isSkipped": false, + "isTodo": false + }, + { + "id": "access-with-valid-user-role", + "rawLine": " it.skip('Access with valid user role', async () => {", + "line": " it.skip('Access with valid user role')", + "label": "Access with valid user role", + "indent": 4, + "type": "it", + "isSkipped": true, + "isTodo": false + }, + { + "id": "access-with-invalid-user-role", + "rawLine": " it.skip('Access with invalid user role', async () => {});", + "line": " it.skip('Access with invalid user role')", + "label": "Access with invalid user role", + "indent": 4, + "type": "it", + "isSkipped": true, + "isTodo": false + }, + { + "id": "access-with-custom-roles---rule-page", + "rawLine": " describe('Access with custom roles - rule page', async () => {", + "line": " describe('Access with custom roles - rule page')", + "label": "Access with custom roles - rule page", + "indent": 4, + "type": "describe", + "isSkipped": false, + "isTodo": false + }, + { + "id": "access-with-valid-user-role", + "rawLine": " it('Access with valid user role', async () => {", + "line": " it('Access with valid user role')", + "label": "Access with valid user role", + "indent": 6, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "access-with-invalid-user-role", + "rawLine": " it.skip('Access with invalid user role', async () => {});", + "line": " it.skip('Access with invalid user role')", + "label": "Access with invalid user role", + "indent": 6, + "type": "it", + "isSkipped": true, + "isTodo": false + } + ], + "tree": [ + { + "id": "access-with-custom-roles", + "rawLine": " describe('Access with custom roles', async () => {", + "line": " describe('Access with custom roles')", + "label": "Access with custom roles", + "indent": 2, + "type": "describe", + "isSkipped": false, + "isTodo": false, + "children": [ + { + "id": "access-with-valid-user-role", + "rawLine": " it.skip('Access with valid user role', async () => {", + "line": " it.skip('Access with valid user role')", + "label": "Access with valid user role", + "indent": 4, + "type": "it", + "isSkipped": true, + "isTodo": false + }, + { + "id": "access-with-invalid-user-role", + "rawLine": " it.skip('Access with invalid user role', async () => {});", + "line": " it.skip('Access with invalid user role')", + "label": "Access with invalid user role", + "indent": 4, + "type": "it", + "isSkipped": true, + "isTodo": false + }, + { + "id": "access-with-custom-roles---rule-page", + "rawLine": " describe('Access with custom roles - rule page', async () => {", + "line": " describe('Access with custom roles - rule page')", + "label": "Access with custom roles - rule page", + "indent": 4, + "type": "describe", + "isSkipped": false, + "isTodo": false, + "children": [ + { + "id": "access-with-valid-user-role", + "rawLine": " it('Access with valid user role', async () => {", + "line": " it('Access with valid user role')", + "label": "Access with valid user role", + "indent": 6, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "access-with-invalid-user-role", + "rawLine": " it.skip('Access with invalid user role', async () => {});", + "line": " it.skip('Access with invalid user role')", + "label": "Access with invalid user role", + "indent": 6, + "type": "it", + "isSkipped": true, + "isTodo": false + } + ] + } + ] + } + ] + }, { "filePath": "x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts", "fileName": "cis_integration_cnvm.ts", @@ -15516,6 +15986,7 @@ "directory": "x-pack/test/cloud_security_posture_functional", "tags": [ "FTR", + "HAS SKIP", "HAS TODO" ], "lines": [ @@ -15523,7 +15994,10 @@ " describe('Kubernetes Dashboard')", " it('displays accurate summary compliance score')", " describe('TODO - Cloud Dashboard', () => {", - " it('todo - displays accurate summary compliance score', async () => {});" + " it('todo - displays accurate summary compliance score', async () => {});", + " describe('Access with custom roles')", + " it('Access with valid user role')", + " it.skip('todo - Access with invalid user role')" ], "testSuits": [ { @@ -15575,6 +16049,36 @@ "type": "it", "isSkipped": false, "isTodo": true + }, + { + "id": "access-with-custom-roles", + "rawLine": " describe('Access with custom roles', async () => {", + "line": " describe('Access with custom roles')", + "label": "Access with custom roles", + "indent": 4, + "type": "describe", + "isSkipped": false, + "isTodo": false + }, + { + "id": "access-with-valid-user-role", + "rawLine": " it('Access with valid user role', async () => {", + "line": " it('Access with valid user role')", + "label": "Access with valid user role", + "indent": 6, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "todo---access-with-invalid-user-role", + "rawLine": " it.skip('todo - Access with invalid user role', async () => {});", + "line": " it.skip('todo - Access with invalid user role')", + "label": "todo - Access with invalid user role", + "indent": 6, + "type": "it", + "isSkipped": true, + "isTodo": true } ], "tree": [ @@ -15631,6 +16135,38 @@ "isTodo": true } ] + }, + { + "id": "access-with-custom-roles", + "rawLine": " describe('Access with custom roles', async () => {", + "line": " describe('Access with custom roles')", + "label": "Access with custom roles", + "indent": 4, + "type": "describe", + "isSkipped": false, + "isTodo": false, + "children": [ + { + "id": "access-with-valid-user-role", + "rawLine": " it('Access with valid user role', async () => {", + "line": " it('Access with valid user role')", + "label": "Access with valid user role", + "indent": 6, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "todo---access-with-invalid-user-role", + "rawLine": " it.skip('todo - Access with invalid user role', async () => {});", + "line": " it.skip('todo - Access with invalid user role')", + "label": "todo - Access with invalid user role", + "indent": 6, + "type": "it", + "isSkipped": true, + "isTodo": true + } + ] } ] } @@ -16393,7 +16929,10 @@ " it('Remove fields from the Findings DataTable')", " it('Reset fields to default')", " describe('Findings Page - support muting rules')", - " it(`verify only enabled rules appears`)" + " it(`verify only enabled rules appears`)", + " describe('Access with custom roles')", + " it('Access with valid user role')", + " it('Access with invalid user role')" ], "testSuits": [ { @@ -16565,6 +17104,36 @@ "type": "it", "isSkipped": false, "isTodo": false + }, + { + "id": "access-with-custom-roles", + "rawLine": " describe('Access with custom roles', async () => {", + "line": " describe('Access with custom roles')", + "label": "Access with custom roles", + "indent": 4, + "type": "describe", + "isSkipped": false, + "isTodo": false + }, + { + "id": "access-with-valid-user-role", + "rawLine": " it('Access with valid user role', async () => {", + "line": " it('Access with valid user role')", + "label": "Access with valid user role", + "indent": 6, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "access-with-invalid-user-role", + "rawLine": " it('Access with invalid user role', async () => {", + "line": " it('Access with invalid user role')", + "label": "Access with invalid user role", + "indent": 6, + "type": "it", + "isSkipped": false, + "isTodo": false } ], "tree": [ @@ -16751,6 +17320,38 @@ "isTodo": false } ] + }, + { + "id": "access-with-custom-roles", + "rawLine": " describe('Access with custom roles', async () => {", + "line": " describe('Access with custom roles')", + "label": "Access with custom roles", + "indent": 4, + "type": "describe", + "isSkipped": false, + "isTodo": false, + "children": [ + { + "id": "access-with-valid-user-role", + "rawLine": " it('Access with valid user role', async () => {", + "line": " it('Access with valid user role')", + "label": "Access with valid user role", + "indent": 6, + "type": "it", + "isSkipped": false, + "isTodo": false + }, + { + "id": "access-with-invalid-user-role", + "rawLine": " it('Access with invalid user role', async () => {", + "line": " it('Access with invalid user role')", + "label": "Access with invalid user role", + "indent": 6, + "type": "it", + "isSkipped": false, + "isTodo": false + } + ] } ] }, diff --git a/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_findings_transform.ts b/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_findings_transform.ts index 6697dbdbbea56..556ab0c7c830c 100644 --- a/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_findings_transform.ts +++ b/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_findings_transform.ts @@ -16,7 +16,7 @@ const LATEST_FINDINGS_TRANSFORM_V830 = 'cloud_security_posture.findings_latest-d const LATEST_FINDINGS_TRANSFORM_V840 = 'cloud_security_posture.findings_latest-default-8.4.0'; const LATEST_FINDINGS_TRANSFORM_V880 = 'cloud_security_posture.findings_latest-default-8.8.0'; -const CURRENT_FINDINGS_TRANSFORM = 'cloud_security_posture.findings_latest-default-8.15.0'; +const CURRENT_FINDINGS_TRANSFORM_VERSION = 'cloud_security_posture.findings_latest-default-8.15.0'; export const DEPRECATED_FINDINGS_TRANSFORMS_VERSION = [ LATEST_FINDINGS_TRANSFORM_V830, @@ -25,7 +25,7 @@ export const DEPRECATED_FINDINGS_TRANSFORMS_VERSION = [ ]; export const latestFindingsTransform: TransformPutTransformRequest = { - transform_id: CURRENT_FINDINGS_TRANSFORM, + transform_id: CURRENT_FINDINGS_TRANSFORM_VERSION, description: 'Defines findings transformation to view only the latest finding per resource', source: { index: FINDINGS_INDEX_PATTERN, diff --git a/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_vulnerabilities_transforms.ts b/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_vulnerabilities_transforms.ts index 2be5cf6072cf6..c7cd2dd0921f7 100644 --- a/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_vulnerabilities_transforms.ts +++ b/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_vulnerabilities_transforms.ts @@ -13,14 +13,15 @@ import { VULNERABILITIES_INDEX_PATTERN, } from '../../common/constants'; -const CURRENT_VULN_VERSION = 'cloud_security_posture.vulnerabilities_latest-default-8.15.0'; +const CURRENT_VULN_TRANSFORM_VERSION = + 'cloud_security_posture.vulnerabilities_latest-default-8.15.0'; export const DEPRECATED_VULN_TRANSFORM_VERSIONS = [ 'cloud_security_posture.vulnerabilities_latest-default-8.8.0', ]; export const latestVulnerabilitiesTransform: TransformPutTransformRequest = { - transform_id: CURRENT_VULN_VERSION, + transform_id: CURRENT_VULN_TRANSFORM_VERSION, description: 'Defines vulnerabilities transformation to view only the latest vulnerability per resource', source: { diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/benchmark_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/benchmark_page.ts new file mode 100644 index 0000000000000..39856fa34d3fb --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/page_objects/benchmark_page.ts @@ -0,0 +1,59 @@ +/* + * 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 expect from '@kbn/expect'; +import { + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +export const CSP_BECNHMARK_TABLE = 'csp_benchmarks_table'; + +export function BenchmarkPagePageProvider({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common', 'header']); + const retry = getService('retry'); + const supertest = getService('supertest'); + const log = getService('log'); + + /** + * required before indexing findings + */ + const waitForPluginInitialized = (): Promise => + retry.try(async () => { + log.debug('Check CSP plugin is initialized'); + const response = await supertest + .get('/internal/cloud_security_posture/status?check=init') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .expect(200); + expect(response.body).to.eql({ isPluginInitialized: true }); + log.debug('CSP plugin is initialized'); + }); + + const benchmarkPage = { + doesBenchmarkTableExists: async () => { + return await testSubjects.find('csp_benchmarks_table'); + }, + }; + + const navigateToBenchnmarkPage = async () => { + await PageObjects.common.navigateToUrl( + 'securitySolution', // Defined in Security Solution plugin + `cloud_security_posture/benchmarks/`, + { shouldUseHashForSubUrl: false } + ); + await PageObjects.header.waitUntilLoadingHasFinished(); + }; + + return { + waitForPluginInitialized, + navigateToBenchnmarkPage, + benchmarkPage, + }; +} diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts index bc1ae63cea51e..17cd9f581c6be 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts @@ -337,6 +337,10 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider return trueOrFalse; }; + const getUnprivilegedPrompt = async () => { + return await testSubjects.find('status-api-unprivileged'); + }; + return { navigateToLatestFindingsPage, navigateToLatestVulnerabilitiesPage, @@ -356,5 +360,6 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider findingsGrouping, createDataTableObject, isLatestFindingsTableThere, + getUnprivilegedPrompt, }; } diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/index.ts b/x-pack/test/cloud_security_posture_functional/page_objects/index.ts index 020341fdd811b..704f6310cdbb2 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/index.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/index.ts @@ -10,6 +10,8 @@ import { FindingsPageProvider } from './findings_page'; import { CspDashboardPageProvider } from './csp_dashboard_page'; import { AddCisIntegrationFormPageProvider } from './add_cis_integration_form_page'; import { VulnerabilityDashboardPageProvider } from './vulnerability_dashboard_page_object'; +import { BenchmarkPagePageProvider } from './benchmark_page'; +import { CspSecurityCommonProvider } from './security_common'; import { RulePagePageProvider } from './rule_page'; export const cloudSecurityPosturePageObjects = { @@ -18,6 +20,8 @@ export const cloudSecurityPosturePageObjects = { cisAddIntegration: AddCisIntegrationFormPageProvider, vulnerabilityDashboard: VulnerabilityDashboardPageProvider, rule: RulePagePageProvider, + benchmark: BenchmarkPagePageProvider, + cspSecurity: CspSecurityCommonProvider, }; export const pageObjects = { ...xpackFunctionalPageObjects, diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/security_common.ts b/x-pack/test/cloud_security_posture_functional/page_objects/security_common.ts new file mode 100644 index 0000000000000..4d5baaa6a2ff9 --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/page_objects/security_common.ts @@ -0,0 +1,128 @@ +/* + * 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 { FtrProviderContext } from '../ftr_provider_context'; + +export function CspSecurityCommonProvider({ getPageObjects, getService }: FtrProviderContext) { + const security = getService('security'); + const pageObjects = getPageObjects(['security']); + + const roles = [ + { + name: 'csp_viewer', + elasticsearch: { + indices: [ + { + names: ['logs-cloud_security_posture.findings-*'], + privileges: ['read'], + }, + { + names: ['logs-cloud_security_posture.findings_latest-*'], + privileges: ['read'], + }, + { + names: ['logs-cloud_security_posture.scores-*'], + privileges: ['read'], + }, + ], + }, + kibana: [ + { + base: ['all'], + spaces: ['*'], + }, + ], + }, + { + name: 'missing_access_findings_latest_role', + elasticsearch: { + indices: [ + { + names: ['logs-cloud_security_posture.findings-*'], + privileges: ['read'], + }, + { + names: ['logs-cloud_security_posture.scores-*'], + privileges: ['read'], + }, + ], + }, + kibana: [ + { + base: ['all'], + spaces: ['*'], + }, + ], + }, + ]; + + const users = [ + { + name: 'csp_read_user', + full_name: 'csp viewer', + password: 'test123', + roles: ['csp_viewer'], + }, + { + name: 'csp_missing_latest_findings_access_user', + full_name: 'missing latest findings index access', + password: 'csp123', + roles: ['missing_access_findings_latest_role'], + }, + ]; + + return { + async createRoles() { + for (const role of roles) { + await security.role.create(role.name, { + elasticsearch: role.elasticsearch, + kibana: role.kibana, + }); + } + }, + + async createUsers() { + for (const user of users) { + await security.user.create(user.name, { + password: user.password, + roles: user.roles, + full_name: user.full_name, + }); + } + }, + + async login(user: string) { + await pageObjects.security.login(user, this.getPasswordForUser(user), { + expectSpaceSelector: false, + }); + }, + + async logout() { + await pageObjects.security.forceLogout(); + }, + + async cleanRoles() { + for (const role of roles) { + await security.role.delete(role.name); + } + }, + + async cleanUsers() { + for (const user of users) { + await security.user.delete(user.name); + } + }, + + getPasswordForUser(user: string): string { + const userConfig = users.find((u) => u.name === user); + if (userConfig === undefined) { + throw new Error(`Can't log in user ${user} - not defined`); + } + return userConfig.password; + }, + }; +} diff --git a/x-pack/test/cloud_security_posture_functional/pages/benchmark.ts b/x-pack/test/cloud_security_posture_functional/pages/benchmark.ts new file mode 100644 index 0000000000000..7eca494108e87 --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/pages/benchmark.ts @@ -0,0 +1,79 @@ +/* + * 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 expect from '@kbn/expect'; +import { k8sFindingsMock } from '../mocks/latest_findings_mock'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const pageObjects = getPageObjects([ + 'common', + 'cspSecurity', + 'cloudPostureDashboard', + 'rule', + 'benchmark', + 'findings', + ]); + + describe('Access with custom roles', async () => { + let cspSecurity = pageObjects.cspSecurity; + let rule: typeof pageObjects.rule; + let benchmark: typeof pageObjects.benchmark; + let findings: typeof pageObjects.findings; + + before(async () => { + benchmark = pageObjects.benchmark; + cspSecurity = pageObjects.cspSecurity; + await benchmark.waitForPluginInitialized(); + await kibanaServer.savedObjects.clean({ + types: ['cloud-security-posture-settings'], + }); + }); + + // Blocked by https://github.com/elastic/kibana/issues/184621 + it.skip('Access with valid user role', async () => { + await cspSecurity.logout(); + await cspSecurity.login('csp_read_user'); + await benchmark.navigateToBenchnmarkPage(); + expect(await benchmark.benchmarkPage.doesBenchmarkTableExists()); + }); + + // Blocked by https://github.com/elastic/kibana/issues/184621 + it.skip('Access with invalid user role', async () => {}); + + // The entire describe block bellow should move to rule.ts byt the page test is blocked by: + // FLAKY: https://github.com/elastic/kibana/issues/178413 + describe('Access with custom roles - rule page', async () => { + before(async () => { + findings = pageObjects.findings; + rule = pageObjects.rule; + await findings.index.add(k8sFindingsMock); + }); + after(async () => { + await findings.index.remove(); + }); + + afterEach(async () => { + // force logout to prevent the next test from failing + await cspSecurity.logout(); + }); + + it('Access with valid user role', async () => { + await cspSecurity.logout(); + await cspSecurity.login('csp_read_user'); + await rule.navigateToRulePage('cis_k8s', '1.0.1'); + + expect(await rule.rulePage.toggleBulkActionButton()); + }); + + // Blocked by https://github.com/elastic/kibana/issues/184621 + it.skip('Access with invalid user role', async () => {}); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts b/x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts index 3faaa849c537c..6d824df8ef4c4 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/compliance_dashboard.ts @@ -12,7 +12,7 @@ import type { FtrProviderContext } from '../ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function ({ getPageObjects, getService }: FtrProviderContext) { const retry = getService('retry'); - const pageObjects = getPageObjects(['common', 'cloudPostureDashboard', 'header']); + const pageObjects = getPageObjects(['common', 'cspSecurity', 'cloudPostureDashboard', 'header']); const chance = new Chance(); const data = [ @@ -36,10 +36,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { this.tags(['cloud_security_posture_compliance_dashboard']); let cspDashboard: typeof pageObjects.cloudPostureDashboard; let dashboard: typeof pageObjects.cloudPostureDashboard.dashboard; + let cspSecurity = pageObjects.cspSecurity; before(async () => { cspDashboard = pageObjects.cloudPostureDashboard; dashboard = pageObjects.cloudPostureDashboard.dashboard; + cspSecurity = pageObjects.cspSecurity; + await cspDashboard.waitForPluginInitialized(); await cspDashboard.index.add(data); @@ -66,5 +69,27 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // describe('TODO - Cloud Dashboard', () => { // it('todo - displays accurate summary compliance score', async () => {}); // }); + + describe('Access with custom roles', async () => { + this.afterEach(async () => { + // force logout to prevent the next test from failing + await cspSecurity.logout(); + }); + it('Access with valid user role', async () => { + await cspSecurity.logout(); + await cspSecurity.login('csp_read_user'); + await cspDashboard.navigateToComplianceDashboardPage(); + await retry.waitFor( + 'Cloud posture integration dashboard to be displayed', + async () => !!dashboard.getIntegrationDashboardContainer() + ); + const scoreElement = await dashboard.getKubernetesComplianceScore(); + + expect((await scoreElement.getVisibleText()) === '0%').to.be(true); // based on the ingested findings + }); + + // Blocked by https://github.com/elastic/kibana/issues/184621 + it.skip('todo - Access with invalid user role', async () => {}); + }); }); } diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings.ts b/x-pack/test/cloud_security_posture_functional/pages/findings.ts index f599648d0c2de..6819da2a03e09 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings.ts @@ -23,7 +23,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const retry = getService('retry'); const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); - const pageObjects = getPageObjects(['common', 'findings', 'header']); + const pageObjects = getPageObjects(['common', 'cspSecurity', 'findings', 'header']); const chance = new Chance(); const timeFiveHoursAgo = (Date.now() - 18000000).toString(); @@ -120,6 +120,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { let findings: typeof pageObjects.findings; let latestFindingsTable: typeof findings.latestFindingsTable; let distributionBar: typeof findings.distributionBar; + let cspSecurity = pageObjects.cspSecurity; beforeEach(async () => { await kibanaServer.savedObjects.clean({ @@ -129,6 +130,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { findings = pageObjects.findings; latestFindingsTable = findings.latestFindingsTable; distributionBar = findings.distributionBar; + cspSecurity = pageObjects.cspSecurity; // Before we start any test we must wait for cloud_security_posture plugin to complete its initialization await findings.waitForPluginInitialized(); @@ -391,5 +393,30 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(await latestFindingsTable.getFindingsCount('passed')).to.eql(passedFindingsCount); }); }); + + describe('Access with custom roles', async () => { + this.afterEach(async () => { + // force logout to prevent the next test from failing + await cspSecurity.logout(); + }); + + it('Access with valid user role', async () => { + await cspSecurity.logout(); + await cspSecurity.login('csp_read_user'); + await findings.navigateToLatestFindingsPage(); + pageObjects.header.waitUntilLoadingHasFinished(); + expect(await latestFindingsTable.getRowsCount()).to.be.greaterThan(0); + }); + + it('Access with invalid user role', async () => { + await cspSecurity.logout(); + await cspSecurity.login('csp_missing_latest_findings_access_user'); + + await findings.navigateToLatestFindingsPage(); + + pageObjects.header.waitUntilLoadingHasFinished(); + expect(await findings.getUnprivilegedPrompt()); + }); + }); }); } diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts b/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts index a7f36230bb1a5..ff77372b5ed23 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts @@ -158,6 +158,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await findings.navigateToLatestFindingsPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); const groupSelector = await findings.groupSelector(); await groupSelector.openDropDown(); await groupSelector.setValue('None'); diff --git a/x-pack/test/cloud_security_posture_functional/pages/index.ts b/x-pack/test/cloud_security_posture_functional/pages/index.ts index a1f9177f05c08..1edf38dc41ec9 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/index.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/index.ts @@ -8,8 +8,17 @@ import { FtrProviderContext } from '../ftr_provider_context'; // eslint-disable-next-line import/no-default-export -export default function ({ loadTestFile }: FtrProviderContext) { +export default function ({ getPageObjects, loadTestFile }: FtrProviderContext) { + const pageObjects = getPageObjects(['cspSecurity']); describe('Cloud Security Posture', function () { + let cspSecurity = pageObjects.cspSecurity; + + before(async () => { + cspSecurity = pageObjects.cspSecurity; + await cspSecurity.createRoles(); + await cspSecurity.createUsers(); + }); + loadTestFile(require.resolve('./rules')); loadTestFile(require.resolve('./findings_onboarding')); loadTestFile(require.resolve('./findings')); @@ -26,5 +35,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./findings_old_data')); loadTestFile(require.resolve('./vulnerabilities')); loadTestFile(require.resolve('./vulnerabilities_grouping')); + loadTestFile(require.resolve('./benchmark')); }); } From 4b5b00f6c631f376deae7024281ecd044de7d32c Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Thu, 6 Jun 2024 13:27:05 +0200 Subject: [PATCH 06/87] [security-in-core] flag APIs as deprecated (#184827) ## Summary Part of https://github.com/elastic/kibana/issues/174578 Flag as deprecated the APIs from the security plugin that are now re-exposed from Core --- x-pack/packages/security/plugin_types_public/src/plugin.ts | 6 ++++++ x-pack/packages/security/plugin_types_server/src/plugin.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/x-pack/packages/security/plugin_types_public/src/plugin.ts b/x-pack/packages/security/plugin_types_public/src/plugin.ts index 672be02cf38d4..06f3574388a36 100644 --- a/x-pack/packages/security/plugin_types_public/src/plugin.ts +++ b/x-pack/packages/security/plugin_types_public/src/plugin.ts @@ -14,6 +14,8 @@ import type { UserProfileAPIClient } from './user_profile'; export interface SecurityPluginSetup { /** * Exposes authentication information about the currently logged in user. + * + * @deprecated in favor of Core's `security` service */ authc: AuthenticationServiceSetup; /** @@ -33,6 +35,8 @@ export interface SecurityPluginStart { navControlService: SecurityNavControlServiceStart; /** * Exposes authentication information about the currently logged in user. + * + * @deprecated in favor of Core's `security` service */ authc: AuthenticationServiceStart; /** @@ -41,6 +45,8 @@ export interface SecurityPluginStart { authz: AuthorizationServiceStart; /** * A set of methods to work with Kibana user profiles. + * + * @deprecated in favor of Core's `userProfile` service. */ userProfiles: UserProfileAPIClient; } diff --git a/x-pack/packages/security/plugin_types_server/src/plugin.ts b/x-pack/packages/security/plugin_types_server/src/plugin.ts index d3ee046c2d0cd..c8222163785bf 100644 --- a/x-pack/packages/security/plugin_types_server/src/plugin.ts +++ b/x-pack/packages/security/plugin_types_server/src/plugin.ts @@ -21,6 +21,8 @@ export interface SecurityPluginSetup { license: SecurityLicense; /** * Exposes services for audit logging. + * + * @deprecated in favor of Core's `security` service */ audit: AuditServiceSetup; /** @@ -35,6 +37,8 @@ export interface SecurityPluginSetup { export interface SecurityPluginStart { /** * Authentication services to confirm the user is who they say they are. + * + * @deprecated in favor of Core's `security` service */ authc: AuthenticationServiceStart; /** @@ -43,6 +47,8 @@ export interface SecurityPluginStart { authz: AuthorizationServiceSetup; /** * User profiles services to retrieve user profiles. + * + * @deprecated in favor of Core's `userProfile` service */ userProfiles: UserProfileServiceStart; } From 4ac05a265c9f3fccaac9028d33ef6416d35bfe1b Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 6 Jun 2024 13:34:12 +0200 Subject: [PATCH 07/87] [TableListView] Persist table sorting (#184667) ## Summary Close https://github.com/elastic/kibana/issues/175457 Persist table sorting option. Memory is separate per table (e.g. different for dashboard/visualization) --- .../src/components/index.ts | 2 +- .../src/components/table_sort_select.tsx | 37 ++++++++++++++++ .../table_list_view_table/src/reducer.tsx | 9 +--- .../src/table_list_view.test.tsx | 28 ++++++++++++- .../src/table_list_view_table.tsx | 42 +++++++++++-------- 5 files changed, 90 insertions(+), 28 deletions(-) diff --git a/packages/content-management/table_list_view_table/src/components/index.ts b/packages/content-management/table_list_view_table/src/components/index.ts index a4a09a5e6bbc6..0448fb90ecb4b 100644 --- a/packages/content-management/table_list_view_table/src/components/index.ts +++ b/packages/content-management/table_list_view_table/src/components/index.ts @@ -14,4 +14,4 @@ export { ItemDetails } from './item_details'; export { TableSortSelect } from './table_sort_select'; export { TagFilterPanel } from './tag_filter_panel'; -export type { SortColumnField } from './table_sort_select'; +export { type SortColumnField, getInitialSorting, saveSorting } from './table_sort_select'; diff --git a/packages/content-management/table_list_view_table/src/components/table_sort_select.tsx b/packages/content-management/table_list_view_table/src/components/table_sort_select.tsx index 9140c8ac3bc32..c9e06a29e9c8c 100644 --- a/packages/content-management/table_list_view_table/src/components/table_sort_select.tsx +++ b/packages/content-management/table_list_view_table/src/components/table_sort_select.tsx @@ -177,3 +177,40 @@ export function TableSortSelect({ tableSort, hasUpdatedAtMetadata, onChange }: P ); } + +const sortStorageKey = (tableId: string) => `tableSort:${tableId}`; +export function getInitialSorting(tableId: string): { + isDefault: boolean; + tableSort: { + field: SortColumnField; + direction: Direction; + }; +} { + try { + const storedSorting = localStorage.getItem(sortStorageKey(tableId)); + if (storedSorting) { + const tableSort = JSON.parse(storedSorting); + return { isDefault: false, tableSort }; + } + } catch (e) { + // ignore + } + + return { + isDefault: true, + tableSort: { + field: 'attributes.title' as const, + direction: 'asc', + }, + }; +} +export function saveSorting( + tableId: string, + tableSort: { field: SortColumnField; direction: Direction } +) { + try { + localStorage.setItem(sortStorageKey(tableId), JSON.stringify(tableSort)); + } catch (e) { + /* empty */ + } +} diff --git a/packages/content-management/table_list_view_table/src/reducer.tsx b/packages/content-management/table_list_view_table/src/reducer.tsx index e96f8fc394347..b4cf3691f9d75 100644 --- a/packages/content-management/table_list_view_table/src/reducer.tsx +++ b/packages/content-management/table_list_view_table/src/reducer.tsx @@ -11,8 +11,6 @@ import type { State } from './table_list_view_table'; import type { Action } from './actions'; export function getReducer() { - let sortColumnChanged = false; - return (state: State, action: Action): State => { switch (action.type) { case 'onFetchItems': { @@ -35,7 +33,7 @@ export function getReducer() { // Only change the table sort if it hasn't been changed already. // For example if its state comes from the URL, we don't want to override it here. - if (hasUpdatedAtMetadata && !sortColumnChanged) { + if (hasUpdatedAtMetadata && !state.sortColumnChanged) { tableSort = { field: 'updatedAt' as const, direction: 'desc' as const, @@ -89,10 +87,6 @@ export function getReducer() { }; } case 'onTableChange': { - if (action.data.sort) { - sortColumnChanged = true; - } - const tableSort = action.data.sort ?? state.tableSort; const pageIndex = action.data.page?.pageIndex ?? state.pagination.pageIndex; const pageSize = action.data.page?.pageSize ?? state.pagination.pageSize; @@ -109,6 +103,7 @@ export function getReducer() { }, tableSort, tableFilter, + sortColumnChanged: state.sortColumnChanged || Boolean(action.data.sort), }; } case 'showConfirmDeleteItemsModal': { diff --git a/packages/content-management/table_list_view_table/src/table_list_view.test.tsx b/packages/content-management/table_list_view_table/src/table_list_view.test.tsx index ce7ed6aa0bf80..c874747799480 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view.test.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view.test.tsx @@ -72,6 +72,10 @@ describe('TableListView', () => { jest.useFakeTimers({ legacyFakeTimers: true }); }); + beforeEach(() => { + localStorage.clear(); + }); + afterAll(() => { jest.useRealTimers(); }); @@ -506,7 +510,7 @@ describe('TableListView', () => { ]); }); - test('filter select should change the sort order', async () => { + test('filter select should change the sort order and remember the order', async () => { let testBed: TestBed; await act(async () => { @@ -515,7 +519,7 @@ describe('TableListView', () => { }); }); - const { component, table, find } = testBed!; + let { component, table, find } = testBed!; const { openSortSelect } = getActions(testBed!); component.update(); @@ -544,6 +548,26 @@ describe('TableListView', () => { ['z-foo', twoDaysAgoToString], ['a-foo', yesterdayToString], ]); + + expect(localStorage.getItem('tableSort:test')).toBe( + '{"field":"attributes.title","direction":"desc"}' + ); + + component.unmount(); + await act(async () => { + testBed = await setupColumnSorting({ + findItems: jest.fn().mockResolvedValue({ total: hits.length, hits }), + }); + }); + + ({ component, table, find } = testBed!); + component.update(); + ({ tableCellsValues } = table.getMetaData('itemsInMemTable')); + + expect(tableCellsValues).toEqual([ + ['z-foo', twoDaysAgoToString], + ['a-foo', yesterdayToString], + ]); }); test('should update the select option when toggling the column header', async () => { diff --git a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx index 3c5051850cdd3..1053123e80191 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx @@ -43,7 +43,7 @@ import { import { useServices } from './services'; import type { SavedObjectsFindOptionsReference } from './services'; import { getReducer } from './reducer'; -import type { SortColumnField } from './components'; +import { type SortColumnField, getInitialSorting, saveSorting } from './components'; import { useTags } from './use_tags'; import { useInRouterContext, useUrlState } from './use_url_state'; import { RowActions, TableItemsRowActions } from './types'; @@ -144,6 +144,7 @@ export interface State({ return getReducer(); }, []); - const initialState = useMemo>( - () => ({ + const initialState = useMemo>(() => { + const initialSort = getInitialSorting(entityName); + return { items: [], hasNoItems: undefined, totalItems: 0, @@ -373,16 +375,13 @@ function TableListViewTableComp({ pageSize: initialPageSize, pageSizeOptions: uniq([10, 20, 50, initialPageSize]).sort(), }, - tableSort: { - field: 'attributes.title' as const, - direction: 'asc', - }, + tableSort: initialSort.tableSort, + sortColumnChanged: !initialSort.isDefault, tableFilter: { createdBy: [], }, - }), - [initialPageSize] - ); + }; + }, [initialPageSize, entityName]); const [state, dispatch] = useReducer(reducer, initialState); @@ -597,7 +596,7 @@ function TableListViewTableComp({ ), sortable: true, - width: '150px', + width: '120px', }); } @@ -660,7 +659,7 @@ function TableListViewTableComp({ name: i18n.translate('contentManagement.tableList.listing.table.actionTitle', { defaultMessage: 'Actions', }), - width: '100px', + width: `${32 * actions.length}px`, actions, }); } @@ -795,14 +794,18 @@ function TableListViewTableComp({ const onSortChange = useCallback( (field: SortColumnField, direction: Direction) => { + const sort = { + field, + direction, + }; + // persist the sorting changes caused by explicit user's interaction + saveSorting(entityName, sort); + updateTableSortFilterAndPagination({ - sort: { - field, - direction, - }, + sort, }); }, - [updateTableSortFilterAndPagination] + [entityName, updateTableSortFilterAndPagination] ); const onFilterChange = useCallback( @@ -838,6 +841,9 @@ function TableListViewTableComp({ field: fieldSerialized as SortColumnField, direction: criteria.sort.direction, }; + + // persist the sorting changes caused by explicit user's interaction + saveSorting(entityName, data.sort); } data.page = { @@ -847,7 +853,7 @@ function TableListViewTableComp({ updateTableSortFilterAndPagination(data); }, - [updateTableSortFilterAndPagination] + [updateTableSortFilterAndPagination, entityName] ); const deleteSelectedItems = useCallback(async () => { From 22155aefdc97180c1cc208cdd35a92dceefdd5bf Mon Sep 17 00:00:00 2001 From: Miriam <31922082+MiriamAparicio@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:59:29 +0100 Subject: [PATCH 08/87] [ObsUX] [Infra] Add missing metrics to Docker container view (#184245) Closes https://github.com/elastic/kibana/issues/183354 Metric section ![image](https://github.com/elastic/kibana/assets/31922082/0d85da8b-a651-4557-ac09-e3eee2573c42) How to test - The feature is under a FF, on inventory page go to settings and enable Container view - In containers inventory, select a docker container, you find one, filter by any `docker.` field. Click on a container. - Container details page should be shown Network and DiskIO charts, as well as CPU and Memory, on Metrics section --- .../src/lib/infra/docker_container.ts | 8 +++ .../components/kpis/container_kpi_charts.tsx | 11 ++-- .../use_container_metrics_charts.test.ts | 4 ++ .../hooks/use_container_metrics_charts.ts | 6 ++- .../hooks/use_integration_check.ts | 2 +- .../overview/metrics/container_metrics.tsx | 24 ++++++--- .../container/metrics/charts/disk.ts | 50 +++++++++++++++++++ .../container/metrics/charts/index.ts | 4 ++ .../container/metrics/charts/network.ts | 47 +++++++++++++++++ .../container/metrics/formulas/disk.ts | 25 ++++++++++ .../container/metrics/formulas/index.ts | 6 +++ .../container/metrics/formulas/network.ts | 27 ++++++++++ .../host/metrics/charts/network.ts | 11 ++-- .../shared/charts/constants.ts | 8 +++ .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - .../test/functional/apps/infra/home_page.ts | 4 +- .../functional/apps/infra/node_details.ts | 2 +- 19 files changed, 217 insertions(+), 28 deletions(-) create mode 100644 x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/disk.ts create mode 100644 x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/network.ts create mode 100644 x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/disk.ts create mode 100644 x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/network.ts diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/docker_container.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/docker_container.ts index 03f72ee61bc06..b0dab3da9dabb 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/docker_container.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/docker_container.ts @@ -21,6 +21,10 @@ export class DockerContainer extends Entity { ...this.fields, 'docker.cpu.total.pct': 25, 'docker.memory.usage.pct': 20, + 'docker.network.inbound.bytes': 100, + 'docker.network.outbound.bytes': 200, + 'docker.diskio.read.ops': 10, + 'docker.diskio.write.ops': 20, }); } } @@ -28,6 +32,10 @@ export class DockerContainer extends Entity { export interface DockerContainerMetricsDocument extends DockerContainerDocument { 'docker.cpu.total.pct': number; 'docker.memory.usage.pct': number; + 'docker.network.inbound.bytes': number; + 'docker.network.outbound.bytes': number; + 'docker.diskio.read.ops': number; + 'docker.diskio.write.ops': number; } class DockerContainerMetrics extends Serializable {} diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/components/kpis/container_kpi_charts.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/components/kpis/container_kpi_charts.tsx index 8e4a67526f72c..ca7f3e3787c46 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/components/kpis/container_kpi_charts.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/components/kpis/container_kpi_charts.tsx @@ -38,9 +38,14 @@ export const ContainerKpiCharts = ({ searchSessionId, loading = false, }: ContainerKpiChartsProps) => { - const isK8Container = useIntegrationCheck({ dependsOn: INTEGRATIONS.kubernetesContainer }); - - return isK8Container ? ( + const isDockerContainer = useIntegrationCheck({ dependsOn: INTEGRATIONS.docker }); + const isKubernetesContainer = useIntegrationCheck({ + dependsOn: INTEGRATIONS.kubernetesContainer, + }); + if (!isDockerContainer && !isKubernetesContainer) { + return null; + } + return isKubernetesContainer ? ( { const model = findInventoryModel('container'); - const { cpu, memory } = await model.metrics.getCharts(); + const { cpu, memory, network, diskIO } = await model.metrics.getCharts(); switch (metric) { case 'cpu': return [cpu.xy.dockerContainerCpuUsage]; case 'memory': return [memory.xy.dockerContainerMemoryUsage]; + case 'network': + return [network.xy.dockerContainerRxTx]; + case 'disk': + return [diskIO.xy.dockerContainerDiskIOReadWrite]; default: return []; } diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_integration_check.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_integration_check.ts index 000fee4705828..231cd2fdef8ff 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_integration_check.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_integration_check.ts @@ -12,7 +12,7 @@ export const useIntegrationCheck = ({ dependsOn }: { dependsOn: string }) => { const { metadata } = useMetadataStateContext(); const hasIntegration = useMemo( - () => (metadata?.features ?? []).some((f) => f.name === dependsOn), + () => (metadata?.features ?? []).some((f) => f.name.startsWith(dependsOn)), [metadata?.features, dependsOn] ); diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/metrics/container_metrics.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/metrics/container_metrics.tsx index f14619005eadb..abe14d6d5807a 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/metrics/container_metrics.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/metrics/container_metrics.tsx @@ -20,20 +20,30 @@ interface Props { } export const ContainerMetrics = (props: Props) => { - const isK8sContainer = useIntegrationCheck({ dependsOn: INTEGRATIONS.kubernetesContainer }); + const isDockerContainer = useIntegrationCheck({ dependsOn: INTEGRATIONS.docker }); + const isKubernetesContainer = useIntegrationCheck({ + dependsOn: INTEGRATIONS.kubernetesContainer, + }); + + if (!isDockerContainer && !isKubernetesContainer) { + return null; + } return ( - {isK8sContainer ? ( - <> - - - - ) : ( + {isDockerContainer && ( <> + + + + )} + {!isDockerContainer && isKubernetesContainer && ( + <> + + )} diff --git a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/disk.ts b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/disk.ts new file mode 100644 index 0000000000000..b3dcc2860ccae --- /dev/null +++ b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/disk.ts @@ -0,0 +1,50 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { LensConfigWithId } from '../../../types'; +import { formulas } from '../formulas'; +import { + DEFAULT_XY_FITTING_FUNCTION, + DEFAULT_XY_HIDDEN_AXIS_TITLE, + DEFAULT_XY_LEGEND, + DISK_IOPS_LABEL, +} from '../../../shared/charts/constants'; + +const dockerContainerDiskIOReadWrite: LensConfigWithId = { + id: 'diskIOReadWrite', + chartType: 'xy', + title: DISK_IOPS_LABEL, + layers: [ + { + seriesType: 'area', + type: 'series', + xAxis: '@timestamp', + yAxis: [ + { + ...formulas.dockerContainerDiskIORead, + label: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.metric.label.read', { + defaultMessage: 'Read', + }), + }, + { + ...formulas.dockerContainerDiskIOWrite, + label: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.metric.label.write', { + defaultMessage: 'Write', + }), + }, + ], + }, + ], + ...DEFAULT_XY_FITTING_FUNCTION, + ...DEFAULT_XY_LEGEND, + ...DEFAULT_XY_HIDDEN_AXIS_TITLE, +}; + +export const diskIO = { + xy: { dockerContainerDiskIOReadWrite }, +}; diff --git a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/index.ts b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/index.ts index 6a83e00c9c5c8..f050a16c57ed4 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/index.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/index.ts @@ -7,10 +7,14 @@ import { cpu } from './cpu'; import { memory } from './memory'; +import { network } from './network'; +import { diskIO } from './disk'; export const charts = { cpu, memory, + network, + diskIO, } as const; export type ContainerCharts = typeof charts; diff --git a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/network.ts b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/network.ts new file mode 100644 index 0000000000000..29cc757d77279 --- /dev/null +++ b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/charts/network.ts @@ -0,0 +1,47 @@ +/* + * 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 { + DEFAULT_XY_FITTING_FUNCTION, + DEFAULT_XY_HIDDEN_AXIS_TITLE, + DEFAULT_XY_LEGEND, + NETWORK_LABEL, + RX_LABEL, + TX_LABEL, +} from '../../../shared/charts/constants'; +import { LensConfigWithId } from '../../../types'; +import { formulas } from '../formulas'; + +const dockerContainerRxTx: LensConfigWithId = { + id: 'rxTx', + chartType: 'xy', + title: NETWORK_LABEL, + layers: [ + { + seriesType: 'area', + type: 'series', + xAxis: '@timestamp', + yAxis: [ + { + ...formulas.dockerContainerNetworkRx, + label: RX_LABEL, + }, + { + ...formulas.dockerContainerNetworkTx, + label: TX_LABEL, + }, + ], + }, + ], + ...DEFAULT_XY_FITTING_FUNCTION, + ...DEFAULT_XY_LEGEND, + ...DEFAULT_XY_HIDDEN_AXIS_TITLE, +}; + +export const network = { + xy: { dockerContainerRxTx }, +}; diff --git a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/disk.ts b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/disk.ts new file mode 100644 index 0000000000000..ba0050bad97aa --- /dev/null +++ b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/disk.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 { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder'; +import { DISK_READ_IOPS_LABEL, DISK_WRITE_IOPS_LABEL } from '../../../shared/charts/constants'; + +export const dockerContainerDiskIORead: LensBaseLayer = { + label: DISK_READ_IOPS_LABEL, + value: "counter_rate(max(docker.diskio.read.ops), kql='docker.diskio.read.ops: *')", + format: 'number', + decimals: 0, + normalizeByUnit: 's', +}; + +export const dockerContainerDiskIOWrite: LensBaseLayer = { + label: DISK_WRITE_IOPS_LABEL, + value: "counter_rate(max(docker.diskio.write.ops), kql='docker.diskio.write.ops: *')", + format: 'number', + decimals: 0, + normalizeByUnit: 's', +}; diff --git a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/index.ts b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/index.ts index 2f5e4f7975f7a..5a878b048179a 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/index.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/index.ts @@ -6,11 +6,17 @@ */ import { dockerContainerCpuUsage, k8sContainerCpuUsage } from './cpu'; +import { dockerContainerDiskIORead, dockerContainerDiskIOWrite } from './disk'; import { dockerContainerMemoryUsage, k8sContainerMemoryUsage } from './memory'; +import { dockerContainerNetworkRx, dockerContainerNetworkTx } from './network'; export const formulas = { dockerContainerCpuUsage, dockerContainerMemoryUsage, + dockerContainerNetworkRx, + dockerContainerNetworkTx, + dockerContainerDiskIORead, + dockerContainerDiskIOWrite, k8sContainerCpuUsage, k8sContainerMemoryUsage, } as const; diff --git a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/network.ts b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/network.ts new file mode 100644 index 0000000000000..6c6600fc6463f --- /dev/null +++ b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/container/metrics/formulas/network.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder'; +import { RX_LABEL, TX_LABEL } from '../../../shared/charts/constants'; + +export const dockerContainerNetworkRx: LensBaseLayer = { + label: RX_LABEL, + value: + "average(docker.network.inbound.bytes) * 8 / (max(metricset.period, kql='docker.network.inbound.bytes: *') / 1000)", + format: 'bits', + decimals: 1, + normalizeByUnit: 's', +}; + +export const dockerContainerNetworkTx: LensBaseLayer = { + label: TX_LABEL, + value: + "average(docker.network.outbound.bytes) * 8 / (max(metricset.period, kql='docker.network.outbound.bytes: *') / 1000)", + format: 'bits', + decimals: 1, + normalizeByUnit: 's', +}; diff --git a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/host/metrics/charts/network.ts b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/host/metrics/charts/network.ts index d94dd48db8370..d166870f5bb4b 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/host/metrics/charts/network.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/host/metrics/charts/network.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; import { LensConfigWithId } from '../../../types'; import { formulas } from '../formulas'; import { @@ -14,6 +13,8 @@ import { DEFAULT_XY_HIDDEN_LEGEND, DEFAULT_XY_LEGEND, NETWORK_LABEL, + RX_LABEL, + TX_LABEL, } from '../../../shared/charts/constants'; const rxTx: LensConfigWithId = { @@ -28,15 +29,11 @@ const rxTx: LensConfigWithId = { yAxis: [ { ...formulas.rx, - label: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.network.label.rx', { - defaultMessage: 'Inbound (RX)', - }), + label: RX_LABEL, }, { ...formulas.tx, - label: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.network.label.tx', { - defaultMessage: 'Outbound (TX)', - }), + label: TX_LABEL, }, ], }, diff --git a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/shared/charts/constants.ts b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/shared/charts/constants.ts index 6d6d22c116f43..fb59022803331 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/shared/charts/constants.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/common/inventory_models/shared/charts/constants.ts @@ -170,3 +170,11 @@ export const NETWORK_LABEL = i18n.translate( defaultMessage: 'Network', } ); + +export const RX_LABEL = i18n.translate('xpack.metricsData.assetDetails.metrics.label.networkRx', { + defaultMessage: 'Inbound (RX)', +}); + +export const TX_LABEL = i18n.translate('xpack.metricsData.assetDetails.metrics.label.networkTx', { + defaultMessage: 'Outbound (TX)', +}); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 71c86aac906ce..6c6d4c4648945 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -44747,8 +44747,6 @@ "xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "Lire", "xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "Utilisé", "xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "Écrire", - "xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "Entrant (RX)", - "xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "Sortant (TX)", "xpack.metricsData.hostsPage.goToMetricsSettings": "Vérifier les paramètres", "xpack.metricsData.inventoryModel.container.displayName": "Conteneurs Docker", "xpack.metricsData.inventoryModel.container.singularDisplayName": "Conteneur Docker", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 75a83002c3a40..a527c1302b66a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -44719,8 +44719,6 @@ "xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "読み取り", "xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "使用中", "xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "書き込み", - "xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "受信(RX)", - "xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "送信(TX)", "xpack.metricsData.hostsPage.goToMetricsSettings": "設定を確認", "xpack.metricsData.inventoryModel.container.displayName": "Dockerコンテナー", "xpack.metricsData.inventoryModel.container.singularDisplayName": "Docker コンテナー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 56d67e46ade68..482bbca9941e6 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -44767,8 +44767,6 @@ "xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "读取", "xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "已使用", "xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "写入", - "xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "入站 (RX)", - "xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "出站 (TX)", "xpack.metricsData.hostsPage.goToMetricsSettings": "检查设置", "xpack.metricsData.inventoryModel.container.displayName": "Docker 容器", "xpack.metricsData.inventoryModel.container.singularDisplayName": "Docker 容器", diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index f1de6350b084f..e197715aadedf 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -295,7 +295,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpuUsage', value: '2,500.0%' }, { metric: 'memoryUsage', value: '2,000.0%' }, ].forEach(({ metric, value }) => { - it(`${metric} tile should show ${value}`, async () => { + it.skip(`${metric} tile should show ${value}`, async () => { await retry.tryForTime(3 * 1000, async () => { const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue( metric @@ -309,7 +309,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpu', chartsCount: 1 }, { metric: 'memory', chartsCount: 1 }, ].forEach(({ metric, chartsCount }) => { - it(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => { + it.skip(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => { const containers = await pageObjects.assetDetails.getOverviewTabDockerMetricCharts( metric ); diff --git a/x-pack/test/functional/apps/infra/node_details.ts b/x-pack/test/functional/apps/infra/node_details.ts index 47792ec4bb2ba..4318644c81bb5 100644 --- a/x-pack/test/functional/apps/infra/node_details.ts +++ b/x-pack/test/functional/apps/infra/node_details.ts @@ -663,7 +663,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpu', chartsCount: 1 }, { metric: 'memory', chartsCount: 1 }, ].forEach(({ metric, chartsCount }) => { - it(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => { + it.skip(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => { const charts = await pageObjects.assetDetails.getOverviewTabDockerMetricCharts( metric ); From b4561e7c3e08817dc3d1c01499ee1f4303c8de11 Mon Sep 17 00:00:00 2001 From: Pablo Machado Date: Thu, 6 Jun 2024 14:30:38 +0200 Subject: [PATCH 09/87] [Security Solution] Change risk scoring sum max and simplify risk score calculations (#184638) ## Summary * Update the `RISK_SCORING_SUM_MAX` to the appropriate value based 10.000 alerts (read more on the original issue) * The following risk scoring engine lines can be simplified by no longer multiplying by 100, and instead using the value above directly. I also renamed the constants to improve reliability, I rounded `2.592375848672986` up to `2.5924` so the calculated score won't go above `100`. For `10.000` alerts with a risk score of `100` each the calculated risk score is `99.99906837960884` Risk score calculation for 10_00 alerts with 100 risk score ![Screenshot 2024-06-03 at 11 56 48](https://github.com/elastic/kibana/assets/1490444/00c876ea-388b-4322-b8f8-19fc65f9f833) Risk score calculation for 1_000 alerts with 100 risk score ![Screenshot 2024-06-03 at 11 57 29](https://github.com/elastic/kibana/assets/1490444/929746c2-19e9-4da1-b4b1-c6e56edfc77c) ### User Impact The entity's calculated risk score will slightly increase because we update the normalisation divisor from 261.2 to 2.5924. ### Checklist Delete any items that are not applicable to this PR. - [x] [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 --- .../asset_criticality/helpers.test.ts | 41 +---------- .../asset_criticality/helpers.ts | 19 ------ .../risk_score/calculate_risk_scores.ts | 17 ++--- .../entity_analytics/risk_score/constants.ts | 31 +++++++-- .../risk_score/painless/index.test.ts | 2 +- .../painless/risk_scoring_reduce.painless | 4 +- .../risk_score_calculation.ts | 8 +-- .../risk_score_entity_calculation.ts | 8 +-- .../risk_score_preview.ts | 68 +++++++++---------- .../risk_scoring_task/task_execution.ts | 4 +- 10 files changed, 79 insertions(+), 123 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.test.ts index 9ec395223c937..4c818c4d067e4 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { applyCriticalityToScore, normalize } from './helpers'; +import { applyCriticalityToScore } from './helpers'; describe('applyCriticalityToScore', () => { describe('integer scores', () => { @@ -61,42 +61,3 @@ describe('applyCriticalityToScore', () => { }); }); }); - -describe('normalize', () => { - it('returns 0 if the number is equal to the min', () => { - const result = normalize({ number: 0, min: 0, max: 100 }); - expect(result).toEqual(0); - }); - - it('returns 100 if the number is equal to the max', () => { - const result = normalize({ number: 100, min: 0, max: 100 }); - expect(result).toEqual(100); - }); - - it('returns 50 if the number is halfway between the min and max', () => { - const result = normalize({ number: 50, min: 0, max: 100 }); - expect(result).toEqual(50); - }); - - it('defaults to a min of 0', () => { - const result = normalize({ number: 50, max: 100 }); - expect(result).toEqual(50); - }); - - describe('when the domain is diffrent than the range', () => { - it('returns 0 if the number is equal to the min', () => { - const result = normalize({ number: 20, min: 20, max: 200 }); - expect(result).toEqual(0); - }); - - it('returns 100 if the number is equal to the max', () => { - const result = normalize({ number: 40, min: 30, max: 40 }); - expect(result).toEqual(100); - }); - - it('returns 50 if the number is halfway between the min and max', () => { - const result = normalize({ number: 20, min: 0, max: 40 }); - expect(result).toEqual(50); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts index 137f4763c4c38..3b3330d0d6536 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts @@ -65,22 +65,3 @@ export const bayesianUpdate = ({ const newProbability = priorProbability * modifier; return (max * newProbability) / (1 + newProbability); }; - -/** - * Normalizes a number to the range [0, 100] - * - * @param number - The number to be normalized - * @param min - The minimum possible value of the number. Defaults to 0. - * @param max - The maximum possible value of the number - * - * @returns The updated score with modifiers applied - */ -export const normalize = ({ - number, - min = 0, - max, -}: { - number: number; - min?: number; - max: number; -}) => ((number - min) / (max - min)) * 100; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts index 9f99a9ae4a561..27ef27b80070b 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts @@ -30,18 +30,14 @@ import { import { withSecuritySpan } from '../../../utils/with_security_span'; import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; import type { AssetCriticalityService } from '../asset_criticality/asset_criticality_service'; -import { - applyCriticalityToScore, - getCriticalityModifier, - normalize, -} from '../asset_criticality/helpers'; +import { applyCriticalityToScore, getCriticalityModifier } from '../asset_criticality/helpers'; import { getAfterKeyForIdentifierType, getFieldForIdentifier } from './helpers'; import type { CalculateRiskScoreAggregations, CalculateScoresParams, RiskScoreBucket, } from '../types'; -import { RISK_SCORING_SUM_MAX, RISK_SCORING_SUM_VALUE } from './constants'; +import { RIEMANN_ZETA_VALUE, RIEMANN_ZETA_S_VALUE } from './constants'; import { getPainlessScripts, type PainlessScripts } from './painless'; const formatForResponse = ({ @@ -82,10 +78,7 @@ const formatForResponse = ({ calculated_level: calculatedLevel, calculated_score: riskDetails.value.score, calculated_score_norm: normalizedScoreWithCriticality, - category_1_score: normalize({ - number: riskDetails.value.category_1_score, - max: RISK_SCORING_SUM_MAX, - }), + category_1_score: riskDetails.value.category_1_score / RIEMANN_ZETA_VALUE, // normalize value to be between 0-100 category_1_count: riskDetails.value.category_1_count, notes: riskDetails.value.notes, inputs: riskDetails.value.risk_inputs.map((riskInput) => ({ @@ -150,8 +143,8 @@ const buildIdentifierTypeAggregation = ({ map_script: scriptedMetricPainless.map, combine_script: scriptedMetricPainless.combine, params: { - p: RISK_SCORING_SUM_VALUE, - risk_cap: RISK_SCORING_SUM_MAX, + p: RIEMANN_ZETA_S_VALUE, + risk_cap: RIEMANN_ZETA_VALUE, global_identifier_type_weight: globalIdentifierTypeWeight || 1, }, reduce_script: scriptedMetricPainless.reduce, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts index 6a691eac42734..5f008ebf3d796 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts @@ -6,15 +6,36 @@ */ /** - * The risk scoring algorithm uses a Riemann zeta function to sum an entity's risk inputs to a known, finite value (@see RISK_SCORING_SUM_MAX). It does so by assigning each input a weight based on its position in the list (ordered by score) of inputs. This value represents the complex variable s of Re(s) in traditional Riemann zeta function notation. + * The risk scoring algorithm uses a Riemann zeta function to sum an entity's risk inputs to a known, finite value (@see RIEMANN_ZETA_VALUE). + * It does so by assigning each input a weight based on its position in the list (ordered by score) of inputs. + * This value represents the complex variable s of Re(s) in traditional Riemann zeta function notation. + * + * Read more: https://en.wikipedia.org/wiki/Riemann_zeta_function */ -export const RISK_SCORING_SUM_VALUE = 1.5; +export const RIEMANN_ZETA_S_VALUE = 1.5; /** - * Represents the maximum possible risk score sum. This value is derived from RISK_SCORING_SUM_VALUE, but we store the precomputed value here to be used more conveniently in normalization. - * @see RISK_SCORING_SUM_VALUE + * Represents the value calculated by Riemann Zeta function for RIEMANN_ZETA_S_VALUE with 10.000 iterations (inputs) which is the default alertSampleSizePerShard. + * The maximum unnormalized risk score value is calculated by multiplying RIEMANN_ZETA_S_VALUE by the maximum alert risk_score (100). + * + * This value is derived from RIEMANN_ZETA_S_VALUE, but we store the precomputed value here to be used more conveniently in normalization. @see RIEMANN_ZETA_S_VALUE + * + * The Riemann Zeta value for different number of inputs is: + * | 𝑍(s,inputs) | + * | :---------------------------------------| + * | 𝑍(1.5,10)≈1.9953364933456017 | + * | 𝑍(1.5,100)≈2.412874098703719 | + * | 𝑍(1.5,1000)≈2.5491456029175756 | + * | 𝑍(1.5,10_000)≈2.5923758486729866 | + * | 𝑍(1.5,100_000)≈2.6060508091764736 | + * | 𝑍(1.5,1_000_000)≈2.6103753491852295 | + * | 𝑍(1.5,10_000_000)≈2.611742893169012 | + * | 𝑍(1.5,100_000_000)≈2.6121753486854478 | + * | 𝑍(1.5,1_000_000_000)≈2.6123121030481857 | + * + * Read more: https://en.wikipedia.org/wiki/Riemann_zeta_function */ -export const RISK_SCORING_SUM_MAX = 261.2; +export const RIEMANN_ZETA_VALUE = 2.5924; /** * This value represents the maximum possible risk score after normalization. diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.test.ts index e21a6afeff326..5d25cf38761fe 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.test.ts @@ -17,7 +17,7 @@ describe('getPainlessScripts', () => { "combine": "return state;", "init": "state.inputs = []", "map": "Map fields = new HashMap();fields.put('id', doc['kibana.alert.uuid'].value);fields.put('index', doc['_index'].value);fields.put('time', doc['@timestamp'].value);fields.put('rule_name', doc['kibana.alert.rule.name'].value);fields.put('category', doc['event.kind'].value);fields.put('score', doc['kibana.alert.risk_score'].value);state.inputs.add(fields); ", - "reduce": "Map results = new HashMap();results['notes'] = [];results['category_1_score'] = 0.0;results['category_1_count'] = 0;results['risk_inputs'] = [];results['score'] = 0.0;def inputs = states[0].inputs;Collections.sort(inputs, (a, b) -> b.get('score').compareTo(a.get('score')));for (int i = 0; i < inputs.length; i++) { double current_score = inputs[i].score / Math.pow(i + 1, params.p); if (i < 10) { inputs[i][\\"contribution\\"] = 100 * current_score / params.risk_cap; results['risk_inputs'].add(inputs[i]); } results['category_1_score'] += current_score; results['category_1_count'] += 1; results['score'] += current_score;}results['score'] *= params.global_identifier_type_weight;results['normalized_score'] = 100 * results['score'] / params.risk_cap;return results;", + "reduce": "Map results = new HashMap();results['notes'] = [];results['category_1_score'] = 0.0;results['category_1_count'] = 0;results['risk_inputs'] = [];results['score'] = 0.0;def inputs = states[0].inputs;Collections.sort(inputs, (a, b) -> b.get('score').compareTo(a.get('score')));for (int i = 0; i < inputs.length; i++) { double current_score = inputs[i].score / Math.pow(i + 1, params.p); if (i < 10) { inputs[i]['contribution'] = current_score / params.risk_cap; results['risk_inputs'].add(inputs[i]); } results['category_1_score'] += current_score; results['category_1_count'] += 1; results['score'] += current_score;}results['score'] *= params.global_identifier_type_weight;results['normalized_score'] = results['score'] / params.risk_cap;return results;", } `); }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_reduce.painless b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_reduce.painless index 629a925522590..69295bf07330c 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_reduce.painless +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_reduce.painless @@ -22,7 +22,7 @@ for (int i = 0; i < inputs.length; i++) { double current_score = inputs[i].score / Math.pow(i + 1, params.p); if (i < 10) { - inputs[i]["contribution"] = 100 * current_score / params.risk_cap; + inputs[i]['contribution'] = current_score / params.risk_cap; results['risk_inputs'].add(inputs[i]); } @@ -36,6 +36,6 @@ for (int i = 0; i < inputs.length; i++) { } results['score'] *= params.global_identifier_type_weight; -results['normalized_score'] = 100 * results['score'] / params.risk_cap; +results['normalized_score'] = results['score'] / params.risk_cap; return results; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_calculation.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_calculation.ts index 1dd6b0f9e5766..29451ef9dacbe 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_calculation.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_calculation.ts @@ -138,8 +138,8 @@ export default ({ getService }: FtrProviderContext): void => { expect(score).to.eql({ calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 8.039816232771823, - category_1_score: 8.039816232771821, + calculated_score_norm: 8.10060175898781, + category_1_score: 8.10060175898781, category_1_count: 1, id_field: 'host.name', id_value: 'host-1', @@ -353,8 +353,8 @@ export default ({ getService }: FtrProviderContext): void => { criticality_modifier: 1.5, calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 11.59366948840633, - category_1_score: 8.039816232771821, + calculated_score_norm: 11.677912063468526, + category_1_score: 8.10060175898781, category_1_count: 1, id_field: 'host.name', id_value: 'host-1', diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_entity_calculation.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_entity_calculation.ts index e3ddfbbda4ef2..2f7b7d44898c1 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_entity_calculation.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_entity_calculation.ts @@ -126,8 +126,8 @@ export default ({ getService }: FtrProviderContext): void => { const expectedScore = { calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 8.039816232771823, - category_1_score: 8.039816232771821, + calculated_score_norm: 8.10060175898781, + category_1_score: 8.10060175898781, category_1_count: 1, id_field: 'host.name', id_value: 'host-1', @@ -176,8 +176,8 @@ export default ({ getService }: FtrProviderContext): void => { criticality_modifier: 1.5, calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 11.59366948840633, - category_1_score: 8.039816232771821, + calculated_score_norm: 11.677912063468526, + category_1_score: 8.10060175898781, category_1_count: 1, id_field: 'host.name', id_value: 'host-1', diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_preview.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_preview.ts index 28ebe8dae5f56..dfd7efe8d6583 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_preview.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_score_preview.ts @@ -116,9 +116,9 @@ export default ({ getService }: FtrProviderContext): void => { expect(score).to.eql({ calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 8.039816232771823, + calculated_score_norm: 8.10060175898781, category_1_count: 1, - category_1_score: 8.039816232771821, + category_1_score: 8.10060175898781, id_field: 'host.name', id_value: 'host-1', }); @@ -144,18 +144,18 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 8.039816232771823, + calculated_score_norm: 8.10060175898781, category_1_count: 1, - category_1_score: 8.039816232771821, + category_1_score: 8.10060175898781, id_field: 'host.name', id_value: 'host-1', }, { calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 8.039816232771823, + calculated_score_norm: 8.10060175898781, category_1_count: 1, - category_1_score: 8.039816232771821, + category_1_score: 8.10060175898781, id_field: 'host.name', id_value: 'host-2', }, @@ -177,9 +177,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Unknown', calculated_score: 28.42462120245875, - calculated_score_norm: 10.88232052161514, + calculated_score_norm: 10.964596976723788, category_1_count: 2, - category_1_score: 10.882320521615142, + category_1_score: 10.964596976723788, id_field: 'host.name', id_value: 'host-1', }, @@ -199,9 +199,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Unknown', calculated_score: 47.25513506055279, - calculated_score_norm: 18.091552473412246, + calculated_score_norm: 18.228334771081926, category_1_count: 30, - category_1_score: 18.091552473412246, + category_1_score: 18.228334771081926, id_field: 'host.name', id_value: 'host-1', }, @@ -224,18 +224,18 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Unknown', calculated_score: 47.25513506055279, - calculated_score_norm: 18.091552473412246, + calculated_score_norm: 18.228334771081926, category_1_count: 30, - category_1_score: 18.091552473412246, + category_1_score: 18.228334771081926, id_field: 'host.name', id_value: 'host-1', }, { calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 8.039816232771823, + calculated_score_norm: 8.10060175898781, category_1_count: 1, - category_1_score: 8.039816232771821, + category_1_score: 8.10060175898781, id_field: 'host.name', id_value: 'host-2', }, @@ -255,9 +255,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Unknown', calculated_score: 50.67035607277805, - calculated_score_norm: 19.399064346392823, + calculated_score_norm: 19.545732168175455, category_1_count: 100, - category_1_score: 19.399064346392823, + category_1_score: 19.545732168175455, id_field: 'host.name', id_value: 'host-1', }, @@ -280,9 +280,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Critical', calculated_score: 241.2874098703716, - calculated_score_norm: 92.37649688758484, + calculated_score_norm: 93.07491508654975, category_1_count: 100, - category_1_score: 92.37649688758484, + category_1_score: 93.07491508654975, id_field: 'host.name', id_value: 'host-1', }, @@ -311,9 +311,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Critical', calculated_score: 254.91456029175757, - calculated_score_norm: 97.59362951445543, + calculated_score_norm: 98.33149216623883, category_1_count: 1000, - category_1_score: 97.59362951445543, + category_1_score: 98.33149216623883, id_field: 'host.name', id_value: 'host-1', }, @@ -407,9 +407,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'High', calculated_score: 225.1106801442913, - calculated_score_norm: 86.18326192354185, + calculated_score_norm: 86.83485578779946, category_1_count: 100, - category_1_score: 86.18326192354185, + category_1_score: 86.83485578779946, id_field: 'host.name', id_value: 'host-1', }, @@ -436,9 +436,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Moderate', calculated_score: 120.6437049351858, - calculated_score_norm: 46.18824844379242, + calculated_score_norm: 46.537457543274876, category_1_count: 100, - category_1_score: 92.37649688758484, + category_1_score: 93.07491508654975, id_field: 'host.name', id_value: 'host-1', }, @@ -463,9 +463,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Moderate', calculated_score: 168.9011869092601, - calculated_score_norm: 64.66354782130938, + calculated_score_norm: 65.15244056058482, category_1_count: 100, - category_1_score: 92.37649688758484, + category_1_score: 93.07491508654975, id_field: 'user.name', id_value: 'user-1', }, @@ -492,9 +492,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'Low', calculated_score: 93.23759116471251, - calculated_score_norm: 35.695861854790394, + calculated_score_norm: 35.96574261869793, category_1_count: 50, - category_1_score: 89.23965463697598, + category_1_score: 89.91435654674481, id_field: 'host.name', id_value: 'host-1', }, @@ -504,9 +504,9 @@ export default ({ getService }: FtrProviderContext): void => { { calculated_level: 'High', calculated_score: 186.47518232942502, - calculated_score_norm: 71.39172370958079, + calculated_score_norm: 71.93148523739586, category_1_count: 50, - category_1_score: 89.23965463697598, + category_1_score: 89.91435654674481, id_field: 'user.name', id_value: 'user-1', }, @@ -547,18 +547,18 @@ export default ({ getService }: FtrProviderContext): void => { criticality_modifier: 2.0, calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 14.8830616583983, + calculated_score_norm: 14.987153868113044, category_1_count: 1, - category_1_score: 8.039816232771821, + category_1_score: 8.10060175898781, id_field: 'host.name', id_value: 'host-1', }, { calculated_level: 'Unknown', calculated_score: 21, - calculated_score_norm: 8.039816232771823, + calculated_score_norm: 8.10060175898781, category_1_count: 1, - category_1_score: 8.039816232771821, + category_1_score: 8.10060175898781, id_field: 'host.name', id_value: 'host-2', }, diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_scoring_task/task_execution.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_scoring_task/task_execution.ts index bcdcd9085a7c1..d53ffc707b396 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_scoring_task/task_execution.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/risk_scoring_task/task_execution.ts @@ -274,9 +274,9 @@ export default ({ getService }: FtrProviderContext): void => { criticality_modifier: 2, calculated_level: 'Moderate', calculated_score: 79.81345973382406, - calculated_score_norm: 46.809565696393314, + calculated_score_norm: 47.08016240063269, category_1_count: 10, - category_1_score: 30.55645472198471, + category_1_score: 30.787478681462762, }, ]); }); From 78b31bbeaf75ce99b374d11e3917eddeadc7e932 Mon Sep 17 00:00:00 2001 From: Rickyanto Ang Date: Thu, 6 Jun 2024 05:52:30 -0700 Subject: [PATCH 10/87] [Cloud Security][Quick Wins] Fix for Rules Flyout (#184050) ## Summary Part of Quick Wins, fix for Rules Flyout closing when user clicks on Toaster/Pop up https://github.com/elastic/kibana/assets/8703149/a0d2e7ed-daff-46fd-973e-c268b950e72f --- .../cloud_security_posture/public/pages/rules/rules_flyout.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_flyout.tsx index 3777646917e4a..2301a4a8ebcfe 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_flyout.tsx @@ -99,7 +99,6 @@ export const RuleFlyout = ({ onClose, rule }: RuleFlyoutProps) => { return ( Date: Thu, 6 Jun 2024 15:10:15 +0200 Subject: [PATCH 11/87] [Security Solution] `DetectionRulesClient`: move public methods out and add APM spans (#184820) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Partially addresses: https://github.com/elastic/kibana/issues/184364** ## Summary This PR is second step in refactoring our newly added `detectionRulesClient`. Changes in this PR: - every public method was extracted into its own file for readability - `_createRule`, `_updateRule`, `_patchRule` and `_upgradePrebuiltRuleWithTypeChange` private methods were removed, their code inlined into the public methods - `toggleRuleEnabledOnUpdate`, `validateMlAuth` and `ClientError` were moved to `utils.ts` - methods are now wrapped in `withSecuritySpan` to report perf stats to APM - renamed `*.rules_management_client.test.ts` -> `*.detection_rules_client.test.ts` - now using the whole `detectionRulesClient` in tests, not just separate methods - simplified parameters of `createDetectionRulesClient`. Now 2 parameters are needed instead of 5, **DetectionRulesClient method showing up in APM** Scherm­afbeelding 2024-06-05 om 14 00 36 **Extracted methods** Upon reviewing the private methods in `detection_rules_client.ts`, it became apparent that extracting these methods into separate files may not be the most effective approach to improve readability. The primary reason is that these private methods do not provide clear abstractions, making them difficult to name appropriately. Take `_updateRule` as an example. This method combines an existing rule with a rule update to create an InternalRuleUpdate object, which is then passed to `rulesClient.update`. If we were to extract this into a separate file, we would need to import it for use in the public `updateRule` method. This would result in an `updateRule` method that calls `_updateRule`, creating confusion about what the inner `_updateRule` does. Also, extracting only private methods does not significantly improve readability, as these methods do not contain a large amount of code. So I ended up inlining the code from most of these private methods directly into the public methods. --- .../__mocks__/detection_rules_client.ts | 47 +- ...ustom_rule.detection_rules_client.test.ts} | 56 +-- .../rule_management/create_custom_rule.ts | 36 ++ ...built_rule.detection_rules_client.test.ts} | 53 +-- .../rule_management/create_prebuilt_rule.ts | 41 ++ ...elete_rule.detection_rules_client.test.ts} | 12 +- .../logic/rule_management/delete_rule.ts | 23 + .../rule_management/detection_rules_client.ts | 442 ++---------------- ...mport_rule.detection_rules_client.test.ts} | 81 ++-- .../logic/rule_management/import_rule.ts | 75 +++ ...patch_rule.detection_rules_client.test.ts} | 24 +- .../logic/rule_management/patch_rule.ts | 60 +++ ...pdate_rule.detection_rules_client.test.ts} | 2 +- .../logic/rule_management/update_rule.ts | 59 +++ ...built_rule.detection_rules_client.test.ts} | 18 +- .../rule_management/upgrade_prebuilt_rule.ts | 90 ++++ .../logic/rule_management/utils.ts | 38 ++ .../server/lib/machine_learning/authz.ts | 2 +- .../server/request_context_factory.ts | 20 +- 19 files changed, 587 insertions(+), 592 deletions(-) rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/{create_custom_rule.rule_management_client.test.ts => create_custom_rule.detection_rules_client.test.ts} (76%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/{create_prebuilt_rule.rule_management_client.test.ts => create_prebuilt_rule.detection_rules_client.test.ts} (81%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/{delete_rule.rule_management_client.test.ts => delete_rule.detection_rules_client.test.ts} (60%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/{import_rule.rule_management_client.test.ts => import_rule.detection_rules_client.test.ts} (83%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/{patch_rule.rule_management_client.test.ts => patch_rule.detection_rules_client.test.ts} (90%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/{update_rule.rule_management_client.test.ts => update_rule.detection_rules_client.test.ts} (99%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/{upgrade_prebuilt_rule.rule_management_client.test.ts => upgrade_prebuilt_rule.detection_rules_client.test.ts} (88%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/utils.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/__mocks__/detection_rules_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/__mocks__/detection_rules_client.ts index d320cfbe5315a..2411de933fb1f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/__mocks__/detection_rules_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/__mocks__/detection_rules_client.ts @@ -5,19 +5,7 @@ * 2.0. */ -import type { - IDetectionRulesClient, - CreateRuleOptions, - _UpdateRuleProps, - _PatchRuleProps, -} from '../detection_rules_client'; -import type { RulesClient } from '@kbn/alerting-plugin/server'; -import type { - RuleCreateProps, - RuleObjectId, -} from '../../../../../../../common/api/detection_engine'; -import type { PrebuiltRuleAsset } from '../../../../prebuilt_rules'; -import type { RuleAlertType } from '../../../../rule_schema'; +import type { IDetectionRulesClient } from '../detection_rules_client'; export type DetectionRulesClientMock = jest.Mocked; @@ -39,36 +27,3 @@ export const detectionRulesClientMock: { } = { create: createDetectionRulesClientMock, }; - -/* Mocks for internal methods */ -export const _createRule: jest.Mock< - ( - rulesClient: RulesClient, - params: RuleCreateProps, - options: CreateRuleOptions - ) => Promise -> = jest.fn(); - -export const _updateRule: jest.Mock< - (rulesClient: RulesClient, updateRulePayload: _UpdateRuleProps) => Promise -> = jest.fn(); - -export const patchRuleMock: jest.Mock< - (rulesClient: RulesClient, patchRulePayload: _PatchRuleProps) => Promise -> = jest.fn(); - -export const _upgradePrebuiltRuleWithTypeChange: jest.Mock< - ( - rulesClient: RulesClient, - ruleAsset: PrebuiltRuleAsset, - existingRule: RuleAlertType - ) => Promise -> = jest.fn(); - -export const _toggleRuleEnabledOnUpdate: jest.Mock< - (rulesClient: RulesClient, existingRule: RuleAlertType, enabled: boolean) => Promise -> = jest.fn(); - -export const _deleteRule: jest.Mock< - (rulesClient: RulesClient, deleteRulePayload: { ruleId: RuleObjectId }) => Promise -> = jest.fn(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.rule_management_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.detection_rules_client.test.ts similarity index 76% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.rule_management_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.detection_rules_client.test.ts index 7cf68102d6a83..6053d5109676c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.rule_management_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.detection_rules_client.test.ts @@ -7,8 +7,6 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { createCustomRule } from './detection_rules_client'; - import { getCreateRulesSchemaMock, getCreateMachineLearningRulesSchemaMock, @@ -17,23 +15,28 @@ import { import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../../common/constants'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; +import { createDetectionRulesClient } from './detection_rules_client'; +import type { IDetectionRulesClient } from './detection_rules_client'; jest.mock('../../../../machine_learning/authz'); jest.mock('../../../../machine_learning/validation'); describe('DetectionRulesClient.createCustomRule', () => { let rulesClient: ReturnType; + let detectionRulesClient: IDetectionRulesClient; + const mlAuthz = (buildMlAuthz as jest.Mock)(); beforeEach(() => { jest.resetAllMocks(); rulesClient = rulesClientMock.create(); + detectionRulesClient = createDetectionRulesClient(rulesClient, mlAuthz); }); it('should create a rule with the correct parameters and options', async () => { const params = getCreateRulesSchemaMock(); - await createCustomRule(rulesClient, { params }, mlAuthz); + await detectionRulesClient.createCustomRule({ params }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -44,8 +47,6 @@ describe('DetectionRulesClient.createCustomRule', () => { immutable: false, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); @@ -56,18 +57,16 @@ describe('DetectionRulesClient.createCustomRule', () => { }); await expect( - createCustomRule(rulesClient, { params: getCreateMachineLearningRulesSchemaMock() }, mlAuthz) + detectionRulesClient.createCustomRule({ params: getCreateMachineLearningRulesSchemaMock() }) ).rejects.toThrow('mocked MLAuth error'); expect(rulesClient.create).not.toHaveBeenCalled(); }); it('calls the rulesClient with legacy ML params', async () => { - await createCustomRule( - rulesClient, - { params: getCreateMachineLearningRulesSchemaMock() }, - mlAuthz - ); + await detectionRulesClient.createCustomRule({ + params: getCreateMachineLearningRulesSchemaMock(), + }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -78,23 +77,17 @@ describe('DetectionRulesClient.createCustomRule', () => { immutable: false, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); it('calls the rulesClient with ML params', async () => { - await createCustomRule( - rulesClient, - { - params: { - ...getCreateMachineLearningRulesSchemaMock(), - machine_learning_job_id: ['new_job_1', 'new_job_2'], - }, + await detectionRulesClient.createCustomRule({ + params: { + ...getCreateMachineLearningRulesSchemaMock(), + machine_learning_job_id: ['new_job_1', 'new_job_2'], }, - mlAuthz - ); + }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -105,8 +98,6 @@ describe('DetectionRulesClient.createCustomRule', () => { immutable: false, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); @@ -115,13 +106,9 @@ describe('DetectionRulesClient.createCustomRule', () => { const params = getCreateThreatMatchRulesSchemaMock(); delete params.threat_indicator_path; - await createCustomRule( - rulesClient, - { - params, - }, - mlAuthz - ); + await detectionRulesClient.createCustomRule({ + params, + }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -131,14 +118,13 @@ describe('DetectionRulesClient.createCustomRule', () => { immutable: false, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); it('does not populate a threatIndicatorPath value for other rules if empty', async () => { - await createCustomRule(rulesClient, { params: getCreateRulesSchemaMock() }, mlAuthz); + await detectionRulesClient.createCustomRule({ params: getCreateRulesSchemaMock() }); + expect(rulesClient.create).not.toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ @@ -147,8 +133,6 @@ describe('DetectionRulesClient.createCustomRule', () => { immutable: false, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.ts new file mode 100644 index 0000000000000..c8951d5ff4a65 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_custom_rule.ts @@ -0,0 +1,36 @@ +/* + * 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 { RulesClient } from '@kbn/alerting-plugin/server'; +import type { RuleCreateProps } from '../../../../../../common/api/detection_engine'; +import type { MlAuthz } from '../../../../machine_learning/authz'; +import type { RuleAlertType, RuleParams } from '../../../rule_schema'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; +import { convertCreateAPIToInternalSchema } from '../../normalization/rule_converters'; + +import { validateMlAuth } from './utils'; + +export interface CreateCustomRuleProps { + params: RuleCreateProps; +} + +export const createCustomRule = async ( + rulesClient: RulesClient, + createCustomRulePayload: CreateCustomRuleProps, + mlAuthz: MlAuthz +): Promise => + withSecuritySpan('DetectionRulesClient.createCustomRule', async () => { + const { params } = createCustomRulePayload; + await validateMlAuth(mlAuthz, params.type); + + const internalRule = convertCreateAPIToInternalSchema(params, { immutable: false }); + const rule = await rulesClient.create({ + data: internalRule, + }); + + return rule; + }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.rule_management_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.detection_rules_client.test.ts similarity index 81% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.rule_management_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.detection_rules_client.test.ts index b99f94344332f..c6d80ad412dc5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.rule_management_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.detection_rules_client.test.ts @@ -7,8 +7,6 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { createPrebuiltRule } from './detection_rules_client'; - import { getCreateRulesSchemaMock, getCreateMachineLearningRulesSchemaMock, @@ -17,23 +15,28 @@ import { import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../../common/constants'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; +import { createDetectionRulesClient } from './detection_rules_client'; +import type { IDetectionRulesClient } from './detection_rules_client'; jest.mock('../../../../machine_learning/authz'); jest.mock('../../../../machine_learning/validation'); describe('DetectionRulesClient.createPrebuiltRule', () => { let rulesClient: ReturnType; + let detectionRulesClient: IDetectionRulesClient; + const mlAuthz = (buildMlAuthz as jest.Mock)(); beforeEach(() => { jest.resetAllMocks(); rulesClient = rulesClientMock.create(); + detectionRulesClient = createDetectionRulesClient(rulesClient, mlAuthz); }); it('creates a rule with the correct parameters and options', async () => { const ruleAsset = { ...getCreateRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; - await createPrebuiltRule(rulesClient, { ruleAsset }, mlAuthz); + await detectionRulesClient.createPrebuiltRule({ ruleAsset }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -45,8 +48,6 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { immutable: true, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); @@ -57,7 +58,7 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { throw new Error('mocked MLAuth error'); }); - await expect(createPrebuiltRule(rulesClient, { ruleAsset }, mlAuthz)).rejects.toThrow( + await expect(detectionRulesClient.createPrebuiltRule({ ruleAsset })).rejects.toThrow( 'mocked MLAuth error' ); @@ -70,13 +71,9 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { version: 1, rule_id: 'rule-id', }; - await createPrebuiltRule( - rulesClient, - { - ruleAsset, - }, - mlAuthz - ); + await detectionRulesClient.createPrebuiltRule({ + ruleAsset, + }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -88,8 +85,6 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { immutable: true, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); @@ -101,13 +96,9 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { version: 1, rule_id: 'rule-id', }; - await createPrebuiltRule( - rulesClient, - { - ruleAsset, - }, - mlAuthz - ); + await detectionRulesClient.createPrebuiltRule({ + ruleAsset, + }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -119,8 +110,6 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { immutable: true, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); @@ -129,13 +118,9 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { const ruleAsset = { ...getCreateThreatMatchRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; delete ruleAsset.threat_indicator_path; - await createPrebuiltRule( - rulesClient, - { - ruleAsset, - }, - mlAuthz - ); + await detectionRulesClient.createPrebuiltRule({ + ruleAsset, + }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -146,15 +131,13 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { immutable: true, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); it('does not populate a threatIndicatorPath value for other rules if empty', async () => { const ruleAsset = { ...getCreateRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; - await createPrebuiltRule(rulesClient, { ruleAsset }, mlAuthz); + await detectionRulesClient.createPrebuiltRule({ ruleAsset }); expect(rulesClient.create).not.toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ @@ -164,8 +147,6 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { immutable: true, }), }), - options: {}, - allowMissingConnectorSecrets: undefined, }) ); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.ts new file mode 100644 index 0000000000000..7cf13cec63822 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/create_prebuilt_rule.ts @@ -0,0 +1,41 @@ +/* + * 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 { RulesClient } from '@kbn/alerting-plugin/server'; +import type { PrebuiltRuleAsset } from '../../../prebuilt_rules'; +import type { MlAuthz } from '../../../../machine_learning/authz'; +import type { RuleAlertType, RuleParams } from '../../../rule_schema'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; +import { convertCreateAPIToInternalSchema } from '../../normalization/rule_converters'; + +import { validateMlAuth } from './utils'; + +export interface CreatePrebuiltRuleProps { + ruleAsset: PrebuiltRuleAsset; +} + +export const createPrebuiltRule = async ( + rulesClient: RulesClient, + createPrebuiltRulePayload: CreatePrebuiltRuleProps, + mlAuthz: MlAuthz +): Promise => + withSecuritySpan('DetectionRulesClient.createPrebuiltRule', async () => { + const { ruleAsset } = createPrebuiltRulePayload; + + await validateMlAuth(mlAuthz, ruleAsset.type); + + const internalRule = convertCreateAPIToInternalSchema(ruleAsset, { + immutable: true, + defaultEnabled: false, + }); + + const rule = await rulesClient.create({ + data: internalRule, + }); + + return rule; + }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.rule_management_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.detection_rules_client.test.ts similarity index 60% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.rule_management_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.detection_rules_client.test.ts index d811e5fa21ce0..2182927a373df 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.rule_management_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.detection_rules_client.test.ts @@ -6,18 +6,26 @@ */ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { deleteRule } from './detection_rules_client'; +import { buildMlAuthz } from '../../../../machine_learning/authz'; +import { createDetectionRulesClient } from './detection_rules_client'; +import type { IDetectionRulesClient } from './detection_rules_client'; + +jest.mock('../../../../machine_learning/authz'); describe('DetectionRulesClient.deleteRule', () => { let rulesClient: ReturnType; + let detectionRulesClient: IDetectionRulesClient; + + const mlAuthz = (buildMlAuthz as jest.Mock)(); beforeEach(() => { rulesClient = rulesClientMock.create(); + detectionRulesClient = createDetectionRulesClient(rulesClient, mlAuthz); }); it('should call rulesClient.delete passing the expected ruleId', async () => { const ruleId = 'ruleId'; - await deleteRule(rulesClient, { + await detectionRulesClient.deleteRule({ ruleId, }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.ts new file mode 100644 index 0000000000000..a2b4acfc6a58b --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/delete_rule.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 { RulesClient } from '@kbn/alerting-plugin/server'; +import type { RuleObjectId } from '../../../../../../common/api/detection_engine'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; + +export interface DeleteRuleProps { + ruleId: RuleObjectId; +} + +export const deleteRule = async ( + rulesClient: RulesClient, + deleteRulePayload: DeleteRuleProps +): Promise => + withSecuritySpan('DetectionRulesClient.deleteRule', async () => { + const { ruleId } = deleteRulePayload; + await rulesClient.delete({ id: ruleId }); + }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/detection_rules_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/detection_rules_client.ts index b756943b7de84..c976f6d247ac5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/detection_rules_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/detection_rules_client.ts @@ -6,97 +6,25 @@ */ import type { RulesClient } from '@kbn/alerting-plugin/server'; - -import type { KibanaRequest } from '@kbn/core-http-server'; -import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; -import type { LicensingApiRequestHandlerContext } from '@kbn/licensing-plugin/server'; -import type { SharedServices } from '@kbn/ml-plugin/server/shared_services'; -import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import type { MlAuthz } from '../../../../machine_learning/authz'; -import { buildMlAuthz } from '../../../../machine_learning/authz'; -import type { - RuleCreateProps, - RuleObjectId, - RuleToImport, - PatchRuleRequestBody, - RuleUpdateProps, -} from '../../../../../../common/api/detection_engine'; - -import type { PrebuiltRuleAsset } from '../../../prebuilt_rules'; -import { readRules } from './read_rules'; +import type { RuleAlertType } from '../../../rule_schema'; -import { - convertPatchAPIToInternalSchema, - convertUpdateAPIToInternalSchema, - convertCreateAPIToInternalSchema, -} from '../../normalization/rule_converters'; -import { transformAlertToRuleAction } from '../../../../../../common/detection_engine/transform_actions'; -import type { RuleAlertType, RuleParams } from '../../../rule_schema'; -import { createBulkErrorObject } from '../../../routes/utils'; -import { getIdError } from '../../utils/utils'; -import { throwAuthzError } from '../../../../machine_learning/validation'; - -class ClientError extends Error { - public readonly statusCode: number; - constructor(message: string, statusCode: number) { - super(message); - this.statusCode = statusCode; - } -} +import type { CreateCustomRuleProps } from './create_custom_rule'; +import type { CreatePrebuiltRuleProps } from './create_prebuilt_rule'; +import type { UpdateRuleProps } from './update_rule'; +import type { PatchRuleProps } from './patch_rule'; +import type { DeleteRuleProps } from './delete_rule'; +import type { UpgradePrebuiltRuleProps } from './upgrade_prebuilt_rule'; +import type { ImportRuleProps } from './import_rule'; -export interface CreateRuleOptions { - /* Optionally pass an ID to use for the rule document. If not provided, an ID will be generated. */ - /* This is the ES document ID, NOT the rule_id */ - id?: string; - immutable?: boolean; - defaultEnabled?: boolean; - allowMissingConnectorSecrets?: boolean; -} - -export interface _UpdateRuleProps { - existingRule: RuleAlertType; - ruleUpdate: RuleUpdateProps; -} - -export interface _PatchRuleProps { - existingRule: RuleAlertType; - nextParams: PatchRuleRequestBody; -} - -interface CreateCustomRuleProps { - params: RuleCreateProps; -} - -interface CreatePrebuiltRuleProps { - ruleAsset: PrebuiltRuleAsset; -} - -interface UpdateRuleProps { - ruleUpdate: RuleUpdateProps; -} - -interface PatchRuleProps { - nextParams: PatchRuleRequestBody; -} - -interface DeleteRuleProps { - ruleId: RuleObjectId; -} - -interface UpgradePrebuiltRuleProps { - ruleAsset: PrebuiltRuleAsset; -} - -interface ImportRuleOptions { - allowMissingConnectorSecrets?: boolean; -} - -interface ImportRuleProps { - ruleToImport: RuleToImport; - overwriteRules?: boolean; - options: ImportRuleOptions; -} +import { createCustomRule } from './create_custom_rule'; +import { createPrebuiltRule } from './create_prebuilt_rule'; +import { updateRule } from './update_rule'; +import { patchRule } from './patch_rule'; +import { deleteRule } from './delete_rule'; +import { upgradePrebuiltRule } from './upgrade_prebuilt_rule'; +import { importRule } from './import_rule'; export interface IDetectionRulesClient { createCustomRule: (createCustomRulePayload: CreateCustomRuleProps) => Promise; @@ -114,317 +42,39 @@ export interface IDetectionRulesClient { export const createDetectionRulesClient = ( rulesClient: RulesClient, - request: KibanaRequest, - savedObjectsClient: SavedObjectsClientContract, - licensing: LicensingApiRequestHandlerContext, - ml?: SharedServices -): IDetectionRulesClient => { - const mlAuthz = buildMlAuthz({ - license: licensing.license, - ml, - request, - savedObjectsClient, - }); - - const client = { - createCustomRule: async ( - createCustomRulePayload: CreateCustomRuleProps - ): Promise => { - return createCustomRule(rulesClient, createCustomRulePayload, mlAuthz); - }, - - createPrebuiltRule: async ( - createPrebuiltRulePayload: CreatePrebuiltRuleProps - ): Promise => { - return createPrebuiltRule(rulesClient, createPrebuiltRulePayload, mlAuthz); - }, - - updateRule: async (updateRulePayload: UpdateRuleProps): Promise => { - return updateRule(rulesClient, updateRulePayload, mlAuthz); - }, - - patchRule: async (patchRulePayload: PatchRuleProps): Promise => { - return patchRule(rulesClient, patchRulePayload, mlAuthz); - }, - - deleteRule: async (deleteRulePayload: DeleteRuleProps): Promise => { - return deleteRule(rulesClient, deleteRulePayload); - }, - - upgradePrebuiltRule: async ( - upgradePrebuiltRulePayload: UpgradePrebuiltRuleProps - ): Promise => { - return upgradePrebuiltRule(rulesClient, upgradePrebuiltRulePayload, mlAuthz); - }, - - importRule: async (importRulePayload: ImportRuleProps): Promise => { - return importRule(rulesClient, importRulePayload, mlAuthz); - }, - }; - - return client; -}; - -export const createCustomRule = async ( - rulesClient: RulesClient, - createCustomRulePayload: CreateCustomRuleProps, - mlAuthz: MlAuthz -): Promise => { - const { params } = createCustomRulePayload; - await _validateMlAuth(mlAuthz, params.type); - - const rule = await _createRule(rulesClient, params, { immutable: false }); - return rule; -}; - -export const createPrebuiltRule = async ( - rulesClient: RulesClient, - createPrebuiltRulePayload: CreatePrebuiltRuleProps, - mlAuthz: MlAuthz -): Promise => { - const { ruleAsset } = createPrebuiltRulePayload; - - await _validateMlAuth(mlAuthz, ruleAsset.type); - - const rule = await _createRule(rulesClient, ruleAsset, { - immutable: true, - defaultEnabled: false, - }); - - return rule; -}; - -export const updateRule = async ( - rulesClient: RulesClient, - updateRulePayload: UpdateRuleProps, mlAuthz: MlAuthz -): Promise => { - const { ruleUpdate } = updateRulePayload; - const { rule_id: ruleId, id } = ruleUpdate; - - await _validateMlAuth(mlAuthz, ruleUpdate.type); - - const existingRule = await readRules({ - rulesClient, - ruleId, - id, - }); - - if (existingRule == null) { - const error = getIdError({ id, ruleId }); - throw new ClientError(error.message, error.statusCode); - } - - const update = await _updateRule(rulesClient, { ruleUpdate, existingRule }); - - await _toggleRuleEnabledOnUpdate(rulesClient, existingRule, ruleUpdate.enabled); - - return { ...update, enabled: ruleUpdate.enabled ?? existingRule.enabled }; -}; - -export const patchRule = async ( - rulesClient: RulesClient, - patchRulePayload: PatchRuleProps, - mlAuthz: MlAuthz -): Promise => { - const { nextParams } = patchRulePayload; - const { rule_id: ruleId, id } = nextParams; - - const existingRule = await readRules({ - rulesClient, - ruleId, - id, - }); - - if (existingRule == null) { - const error = getIdError({ id, ruleId }); - throw new ClientError(error.message, error.statusCode); - } - - await _validateMlAuth(mlAuthz, nextParams.type ?? existingRule.params.type); - - const update = await _patchRule(rulesClient, { existingRule, nextParams }); - - await _toggleRuleEnabledOnUpdate(rulesClient, existingRule, nextParams.enabled); - - if (nextParams.enabled != null) { - return { ...update, enabled: nextParams.enabled }; - } else { - return update; - } -}; - -export const deleteRule = async ( - rulesClient: RulesClient, - deleteRulePayload: DeleteRuleProps -): Promise => { - const { ruleId } = deleteRulePayload; - await rulesClient.delete({ id: ruleId }); -}; - -export const upgradePrebuiltRule = async ( - rulesClient: RulesClient, - upgradePrebuiltRulePayload: UpgradePrebuiltRuleProps, - mlAuthz: MlAuthz -): Promise => { - const { ruleAsset } = upgradePrebuiltRulePayload; - - await _validateMlAuth(mlAuthz, ruleAsset.type); - - const existingRule = await readRules({ - rulesClient, - ruleId: ruleAsset.rule_id, - id: undefined, - }); - - if (!existingRule) { - throw new ClientError(`Failed to find rule ${ruleAsset.rule_id}`, 500); - } - - // If rule has change its type during upgrade, delete and recreate it - if (ruleAsset.type !== existingRule.params.type) { - return _upgradePrebuiltRuleWithTypeChange(rulesClient, ruleAsset, existingRule); - } - - // Else, simply patch it. - await _patchRule(rulesClient, { existingRule, nextParams: ruleAsset }); - - const updatedRule = await readRules({ - rulesClient, - ruleId: ruleAsset.rule_id, - id: undefined, - }); - - if (!updatedRule) { - throw new ClientError(`Rule ${ruleAsset.rule_id} not found after upgrade`, 500); - } - - return updatedRule; -}; - -export const importRule = async ( - rulesClient: RulesClient, - importRulePayload: ImportRuleProps, - mlAuthz: MlAuthz -): Promise => { - const { ruleToImport, overwriteRules, options } = importRulePayload; - - await _validateMlAuth(mlAuthz, ruleToImport.type); - - const existingRule = await readRules({ - rulesClient, - ruleId: ruleToImport.rule_id, - id: undefined, - }); - - if (!existingRule) { - return _createRule(rulesClient, ruleToImport, { - immutable: false, - allowMissingConnectorSecrets: options?.allowMissingConnectorSecrets, - }); - } else if (existingRule && overwriteRules) { - return _updateRule(rulesClient, { - existingRule, - ruleUpdate: ruleToImport, - }); - } else { - throw createBulkErrorObject({ - ruleId: existingRule.params.ruleId, - statusCode: 409, - message: `rule_id: "${existingRule.params.ruleId}" already exists`, - }); - } -}; - -/* -------- Internal Methods -------- */ -const _createRule = async ( - rulesClient: RulesClient, - params: RuleCreateProps, - options: CreateRuleOptions -) => { - const rulesClientCreateRuleOptions = options.id ? { id: options.id } : {}; - - const internalRule = convertCreateAPIToInternalSchema(params, options); - const rule = await rulesClient.create({ - data: internalRule, - options: rulesClientCreateRuleOptions, - allowMissingConnectorSecrets: options.allowMissingConnectorSecrets, - }); - - return rule; -}; - -const _updateRule = async ( - rulesClient: RulesClient, - updateRulePayload: _UpdateRuleProps -): Promise => { - const { ruleUpdate, existingRule } = updateRulePayload; - - const newInternalRule = convertUpdateAPIToInternalSchema({ - existingRule, - ruleUpdate, - }); - - const update = await rulesClient.update({ - id: existingRule.id, - data: newInternalRule, - }); - - return update; -}; - -const _patchRule = async ( - rulesClient: RulesClient, - patchRulePayload: _PatchRuleProps -): Promise => { - const { nextParams, existingRule } = patchRulePayload; - - const patchedRule = convertPatchAPIToInternalSchema(nextParams, existingRule); - - const update = await rulesClient.update({ - id: existingRule.id, - data: patchedRule, - }); - - return update; -}; +): IDetectionRulesClient => ({ + createCustomRule: async ( + createCustomRulePayload: CreateCustomRuleProps + ): Promise => { + return createCustomRule(rulesClient, createCustomRulePayload, mlAuthz); + }, + + createPrebuiltRule: async ( + createPrebuiltRulePayload: CreatePrebuiltRuleProps + ): Promise => { + return createPrebuiltRule(rulesClient, createPrebuiltRulePayload, mlAuthz); + }, -const _upgradePrebuiltRuleWithTypeChange = async ( - rulesClient: RulesClient, - ruleAsset: PrebuiltRuleAsset, - existingRule: RuleAlertType -) => { - // If we're trying to change the type of a prepackaged rule, we need to delete the old one - // and replace it with the new rule, keeping the enabled setting, actions, throttle, id, - // and exception lists from the old rule - await rulesClient.delete({ id: existingRule.id }); + updateRule: async (updateRulePayload: UpdateRuleProps): Promise => { + return updateRule(rulesClient, updateRulePayload, mlAuthz); + }, - return _createRule( - rulesClient, - { - ...ruleAsset, - enabled: existingRule.enabled, - exceptions_list: existingRule.params.exceptionsList, - actions: existingRule.actions.map(transformAlertToRuleAction), - timeline_id: existingRule.params.timelineId, - timeline_title: existingRule.params.timelineTitle, - }, - { immutable: true, defaultEnabled: existingRule.enabled, id: existingRule.id } - ); -}; + patchRule: async (patchRulePayload: PatchRuleProps): Promise => { + return patchRule(rulesClient, patchRulePayload, mlAuthz); + }, -const _toggleRuleEnabledOnUpdate = async ( - rulesClient: RulesClient, - existingRule: RuleAlertType, - updatedRuleEnabled?: boolean -) => { - if (existingRule.enabled && updatedRuleEnabled === false) { - await rulesClient.disable({ id: existingRule.id }); - } else if (!existingRule.enabled && updatedRuleEnabled === true) { - await rulesClient.enable({ id: existingRule.id }); - } -}; + deleteRule: async (deleteRulePayload: DeleteRuleProps): Promise => { + return deleteRule(rulesClient, deleteRulePayload); + }, -const _validateMlAuth = async (mlAuthz: MlAuthz, ruleType: Type) => { - throwAuthzError(await mlAuthz.validateRuleType(ruleType)); -}; + upgradePrebuiltRule: async ( + upgradePrebuiltRulePayload: UpgradePrebuiltRuleProps + ): Promise => { + return upgradePrebuiltRule(rulesClient, upgradePrebuiltRulePayload, mlAuthz); + }, + + importRule: async (importRulePayload: ImportRuleProps): Promise => { + return importRule(rulesClient, importRulePayload, mlAuthz); + }, +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.rule_management_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.detection_rules_client.test.ts similarity index 83% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.rule_management_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.detection_rules_client.test.ts index cc7ae2bf28038..f783c5963c2be 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.rule_management_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.detection_rules_client.test.ts @@ -6,13 +6,14 @@ */ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { importRule } from './detection_rules_client'; import { readRules } from './read_rules'; import { getCreateRulesSchemaMock } from '../../../../../../common/api/detection_engine/model/rule_schema/mocks'; import { getRuleMock } from '../../../routes/__mocks__/request_responses'; import { getQueryRuleParams } from '../../../rule_schema/mocks'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; +import { createDetectionRulesClient } from './detection_rules_client'; +import type { IDetectionRulesClient } from './detection_rules_client'; jest.mock('../../../../machine_learning/authz'); jest.mock('../../../../machine_learning/validation'); @@ -21,6 +22,8 @@ jest.mock('./read_rules'); describe('DetectionRulesClient.importRule', () => { let rulesClient: ReturnType; + let detectionRulesClient: IDetectionRulesClient; + const mlAuthz = (buildMlAuthz as jest.Mock)(); const immutable = false as const; // Can only take value of false const allowMissingConnectorSecrets = true; @@ -39,19 +42,16 @@ describe('DetectionRulesClient.importRule', () => { beforeEach(() => { rulesClient = rulesClientMock.create(); + detectionRulesClient = createDetectionRulesClient(rulesClient, mlAuthz); }); it('calls rulesClient.create with the correct parameters when rule_id does not match an installed rule', async () => { (readRules as jest.Mock).mockResolvedValue(null); - await importRule( - rulesClient, - { - ruleToImport, - overwriteRules: true, - options: { allowMissingConnectorSecrets }, - }, - mlAuthz - ); + await detectionRulesClient.importRule({ + ruleToImport, + overwriteRules: true, + options: { allowMissingConnectorSecrets }, + }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ @@ -64,7 +64,6 @@ describe('DetectionRulesClient.importRule', () => { version: ruleToImport.version, }), }), - options: {}, allowMissingConnectorSecrets, }) ); @@ -76,15 +75,11 @@ describe('DetectionRulesClient.importRule', () => { }); await expect( - importRule( - rulesClient, - { - ruleToImport, - overwriteRules: true, - options: { allowMissingConnectorSecrets }, - }, - mlAuthz - ) + detectionRulesClient.importRule({ + ruleToImport, + overwriteRules: true, + options: { allowMissingConnectorSecrets }, + }) ).rejects.toThrow('mocked MLAuth error'); expect(rulesClient.create).not.toHaveBeenCalled(); @@ -94,15 +89,11 @@ describe('DetectionRulesClient.importRule', () => { describe('when rule_id matches an installed rule', () => { it('calls rulesClient.update with the correct parameters when overwriteRules is true', async () => { (readRules as jest.Mock).mockResolvedValue(existingRule); - await importRule( - rulesClient, - { - ruleToImport, - overwriteRules: true, - options: { allowMissingConnectorSecrets }, - }, - mlAuthz - ); + await detectionRulesClient.importRule({ + ruleToImport, + overwriteRules: true, + options: { allowMissingConnectorSecrets }, + }); expect(rulesClient.update).toHaveBeenCalledWith( expect.objectContaining({ @@ -136,18 +127,14 @@ describe('DetectionRulesClient.importRule', () => { }; (readRules as jest.Mock).mockResolvedValue(existingRuleWithTimestampOverride); - await importRule( - rulesClient, - { - ruleToImport: { - ...ruleToImport, - timestamp_override: undefined, - }, - overwriteRules: true, - options: { allowMissingConnectorSecrets }, + await detectionRulesClient.importRule({ + ruleToImport: { + ...ruleToImport, + timestamp_override: undefined, }, - mlAuthz - ); + overwriteRules: true, + options: { allowMissingConnectorSecrets }, + }); expect(rulesClient.create).not.toHaveBeenCalled(); expect(rulesClient.update).toHaveBeenCalledWith( @@ -164,15 +151,11 @@ describe('DetectionRulesClient.importRule', () => { it('rejects when overwriteRules is false', async () => { (readRules as jest.Mock).mockResolvedValue(existingRule); await expect( - importRule( - rulesClient, - { - ruleToImport, - overwriteRules: false, - options: { allowMissingConnectorSecrets }, - }, - mlAuthz - ) + detectionRulesClient.importRule({ + ruleToImport, + overwriteRules: false, + options: { allowMissingConnectorSecrets }, + }) ).rejects.toMatchObject({ error: { status_code: 409, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.ts new file mode 100644 index 0000000000000..643d59a0c495f --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/import_rule.ts @@ -0,0 +1,75 @@ +/* + * 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 { RulesClient } from '@kbn/alerting-plugin/server'; +import type { MlAuthz } from '../../../../machine_learning/authz'; +import type { RuleAlertType, RuleParams } from '../../../rule_schema'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; +import type { RuleToImport } from '../../../../../../common/api/detection_engine'; +import { createBulkErrorObject } from '../../../routes/utils'; +import { + convertCreateAPIToInternalSchema, + convertUpdateAPIToInternalSchema, +} from '../../normalization/rule_converters'; + +import { validateMlAuth } from './utils'; + +import { readRules } from './read_rules'; + +interface ImportRuleOptions { + allowMissingConnectorSecrets?: boolean; +} + +export interface ImportRuleProps { + ruleToImport: RuleToImport; + overwriteRules?: boolean; + options: ImportRuleOptions; +} + +export const importRule = async ( + rulesClient: RulesClient, + importRulePayload: ImportRuleProps, + mlAuthz: MlAuthz +): Promise => + withSecuritySpan('DetectionRulesClient.importRule', async () => { + const { ruleToImport, overwriteRules, options } = importRulePayload; + + await validateMlAuth(mlAuthz, ruleToImport.type); + + const existingRule = await readRules({ + rulesClient, + ruleId: ruleToImport.rule_id, + id: undefined, + }); + + if (!existingRule) { + const internalRule = convertCreateAPIToInternalSchema(ruleToImport, { + immutable: false, + }); + + return rulesClient.create({ + data: internalRule, + allowMissingConnectorSecrets: options.allowMissingConnectorSecrets, + }); + } else if (existingRule && overwriteRules) { + const newInternalRule = convertUpdateAPIToInternalSchema({ + existingRule, + ruleUpdate: ruleToImport, + }); + + return rulesClient.update({ + id: existingRule.id, + data: newInternalRule, + }); + } else { + throw createBulkErrorObject({ + ruleId: existingRule.params.ruleId, + statusCode: 409, + message: `rule_id: "${existingRule.params.ruleId}" already exists`, + }); + } + }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.rule_management_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.detection_rules_client.test.ts similarity index 90% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.rule_management_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.detection_rules_client.test.ts index 29bc4c678ac2d..59d250606e285 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.rule_management_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.detection_rules_client.test.ts @@ -13,10 +13,11 @@ import { getCreateMachineLearningRulesSchemaMock, getCreateRulesSchemaMock, } from '../../../../../../common/api/detection_engine/model/rule_schema/mocks'; -import { patchRule } from './detection_rules_client'; import { readRules } from './read_rules'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; +import { createDetectionRulesClient } from './detection_rules_client'; +import type { IDetectionRulesClient } from './detection_rules_client'; jest.mock('../../../../machine_learning/authz'); jest.mock('../../../../machine_learning/validation'); @@ -25,10 +26,13 @@ jest.mock('./read_rules'); describe('DetectionRulesClient.patchRule', () => { let rulesClient: ReturnType; + let detectionRulesClient: IDetectionRulesClient; + const mlAuthz = (buildMlAuthz as jest.Mock)(); beforeEach(() => { rulesClient = rulesClientMock.create(); + detectionRulesClient = createDetectionRulesClient(rulesClient, mlAuthz); }); it('calls the rulesClient with expected params', async () => { @@ -37,7 +41,7 @@ describe('DetectionRulesClient.patchRule', () => { (readRules as jest.Mock).mockResolvedValueOnce(existingRule); rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); - await patchRule(rulesClient, { nextParams }, mlAuthz); + await detectionRulesClient.patchRule({ nextParams }); expect(rulesClient.update).toHaveBeenCalledWith( expect.objectContaining({ @@ -58,7 +62,7 @@ describe('DetectionRulesClient.patchRule', () => { (readRules as jest.Mock).mockResolvedValueOnce(existingRule); rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); - const rule = await patchRule(rulesClient, { nextParams }, mlAuthz); + const rule = await detectionRulesClient.patchRule({ nextParams }); expect(rule.enabled).toBe(true); }); @@ -69,7 +73,7 @@ describe('DetectionRulesClient.patchRule', () => { (readRules as jest.Mock).mockResolvedValueOnce(existingRule); rulesClient.update.mockResolvedValue(getRuleMock(getMlRuleParams())); - await patchRule(rulesClient, { nextParams }, mlAuthz); + await detectionRulesClient.patchRule({ nextParams }); expect(rulesClient.update).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ @@ -91,7 +95,7 @@ describe('DetectionRulesClient.patchRule', () => { (readRules as jest.Mock).mockResolvedValueOnce(existingRule); rulesClient.update.mockResolvedValue(getRuleMock(getMlRuleParams())); - await patchRule(rulesClient, { nextParams }, mlAuthz); + await detectionRulesClient.patchRule({ nextParams }); expect(rulesClient.update).toHaveBeenCalledWith( expect.objectContaining({ @@ -117,7 +121,7 @@ describe('DetectionRulesClient.patchRule', () => { (readRules as jest.Mock).mockResolvedValueOnce(existingRule); rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); - await patchRule(rulesClient, { nextParams }, mlAuthz); + await detectionRulesClient.patchRule({ nextParams }); expect(rulesClient.disable).toHaveBeenCalledWith( expect.objectContaining({ @@ -138,7 +142,7 @@ describe('DetectionRulesClient.patchRule', () => { (readRules as jest.Mock).mockResolvedValueOnce(existingRule); rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); - await patchRule(rulesClient, { nextParams }, mlAuthz); + await detectionRulesClient.patchRule({ nextParams }); expect(rulesClient.enable).toHaveBeenCalledWith( expect.objectContaining({ @@ -157,7 +161,7 @@ describe('DetectionRulesClient.patchRule', () => { enabled: true, }; - await expect(patchRule(rulesClient, { nextParams }, mlAuthz)).rejects.toThrow( + await expect(detectionRulesClient.patchRule({ nextParams })).rejects.toThrow( 'mocked MLAuth error' ); @@ -183,7 +187,7 @@ describe('DetectionRulesClient.patchRule', () => { (readRules as jest.Mock).mockResolvedValueOnce(existingRule); rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); - await patchRule(rulesClient, { nextParams }, mlAuthz); + await detectionRulesClient.patchRule({ nextParams }); expect(rulesClient.update).toHaveBeenCalledWith( expect.objectContaining({ @@ -221,7 +225,7 @@ describe('DetectionRulesClient.patchRule', () => { (readRules as jest.Mock).mockResolvedValueOnce(existingRule); rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); - await patchRule(rulesClient, { nextParams }, mlAuthz); + await detectionRulesClient.patchRule({ nextParams }); expect(rulesClient.update).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.ts new file mode 100644 index 0000000000000..dad3d74a6f208 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/patch_rule.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 type { RulesClient } from '@kbn/alerting-plugin/server'; +import type { PatchRuleRequestBody } from '../../../../../../common/api/detection_engine'; +import type { MlAuthz } from '../../../../machine_learning/authz'; +import type { RuleAlertType } from '../../../rule_schema'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; +import { getIdError } from '../../utils/utils'; +import { convertPatchAPIToInternalSchema } from '../../normalization/rule_converters'; + +import { validateMlAuth, ClientError, toggleRuleEnabledOnUpdate } from './utils'; + +import { readRules } from './read_rules'; + +export interface PatchRuleProps { + nextParams: PatchRuleRequestBody; +} + +export const patchRule = async ( + rulesClient: RulesClient, + patchRulePayload: PatchRuleProps, + mlAuthz: MlAuthz +): Promise => + withSecuritySpan('DetectionRulesClient.patchRule', async () => { + const { nextParams } = patchRulePayload; + const { rule_id: ruleId, id } = nextParams; + + const existingRule = await readRules({ + rulesClient, + ruleId, + id, + }); + + if (existingRule == null) { + const error = getIdError({ id, ruleId }); + throw new ClientError(error.message, error.statusCode); + } + + await validateMlAuth(mlAuthz, nextParams.type ?? existingRule.params.type); + + const patchedRule = convertPatchAPIToInternalSchema(nextParams, existingRule); + + const update = await rulesClient.update({ + id: existingRule.id, + data: patchedRule, + }); + + await toggleRuleEnabledOnUpdate(rulesClient, existingRule, nextParams.enabled); + + if (nextParams.enabled != null) { + return { ...update, enabled: nextParams.enabled }; + } else { + return update; + } + }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.rule_management_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.detection_rules_client.test.ts similarity index 99% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.rule_management_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.detection_rules_client.test.ts index b0ee5a6426775..f538672444b0e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.rule_management_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.detection_rules_client.test.ts @@ -13,7 +13,7 @@ import { getCreateMachineLearningRulesSchemaMock, getCreateRulesSchemaMock, } from '../../../../../../common/api/detection_engine/model/rule_schema/mocks'; -import { updateRule } from './detection_rules_client'; +import { updateRule } from './update_rule'; import { readRules } from './read_rules'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.ts new file mode 100644 index 0000000000000..4370e4f457448 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/update_rule.ts @@ -0,0 +1,59 @@ +/* + * 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 { RulesClient } from '@kbn/alerting-plugin/server'; +import type { RuleUpdateProps } from '../../../../../../common/api/detection_engine'; +import type { MlAuthz } from '../../../../machine_learning/authz'; +import type { RuleAlertType } from '../../../rule_schema'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; +import { getIdError } from '../../utils/utils'; +import { convertUpdateAPIToInternalSchema } from '../../normalization/rule_converters'; + +import { validateMlAuth, ClientError, toggleRuleEnabledOnUpdate } from './utils'; + +import { readRules } from './read_rules'; + +export interface UpdateRuleProps { + ruleUpdate: RuleUpdateProps; +} + +export const updateRule = async ( + rulesClient: RulesClient, + updateRulePayload: UpdateRuleProps, + mlAuthz: MlAuthz +): Promise => + withSecuritySpan('DetectionRulesClient.updateRule', async () => { + const { ruleUpdate } = updateRulePayload; + const { rule_id: ruleId, id } = ruleUpdate; + + await validateMlAuth(mlAuthz, ruleUpdate.type); + + const existingRule = await readRules({ + rulesClient, + ruleId, + id, + }); + + if (existingRule == null) { + const error = getIdError({ id, ruleId }); + throw new ClientError(error.message, error.statusCode); + } + + const newInternalRule = convertUpdateAPIToInternalSchema({ + existingRule, + ruleUpdate, + }); + + const update = await rulesClient.update({ + id: existingRule.id, + data: newInternalRule, + }); + + await toggleRuleEnabledOnUpdate(rulesClient, existingRule, ruleUpdate.enabled); + + return { ...update, enabled: ruleUpdate.enabled ?? existingRule.enabled }; + }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.rule_management_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.detection_rules_client.test.ts similarity index 88% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.rule_management_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.detection_rules_client.test.ts index 1997df6f3fff1..50dc69b660c0f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.rule_management_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.detection_rules_client.test.ts @@ -7,8 +7,6 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { upgradePrebuiltRule } from './detection_rules_client'; - import { getCreateEqlRuleSchemaMock, getCreateRulesSchemaMock, @@ -21,6 +19,8 @@ import { getEqlRuleParams, getQueryRuleParams } from '../../../rule_schema/mocks import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; +import { createDetectionRulesClient } from './detection_rules_client'; +import type { IDetectionRulesClient } from './detection_rules_client'; jest.mock('../../../../machine_learning/authz'); jest.mock('../../../../machine_learning/validation'); @@ -28,10 +28,13 @@ jest.mock('./read_rules'); describe('DetectionRulesClient.upgradePrebuiltRule', () => { let rulesClient: ReturnType; + let detectionRulesClient: IDetectionRulesClient; + const mlAuthz = (buildMlAuthz as jest.Mock)(); beforeEach(() => { rulesClient = rulesClientMock.create(); + detectionRulesClient = createDetectionRulesClient(rulesClient, mlAuthz); }); it('throws if no matching rule_id is found', async () => { @@ -42,7 +45,7 @@ describe('DetectionRulesClient.upgradePrebuiltRule', () => { }; (readRules as jest.Mock).mockResolvedValue(null); - await expect(upgradePrebuiltRule(rulesClient, { ruleAsset }, mlAuthz)).rejects.toThrow( + await expect(detectionRulesClient.upgradePrebuiltRule({ ruleAsset })).rejects.toThrow( `Failed to find rule ${ruleAsset.rule_id}` ); }); @@ -58,7 +61,7 @@ describe('DetectionRulesClient.upgradePrebuiltRule', () => { rule_id: 'rule-id', }; - await expect(upgradePrebuiltRule(rulesClient, { ruleAsset }, mlAuthz)).rejects.toThrow( + await expect(detectionRulesClient.upgradePrebuiltRule({ ruleAsset })).rejects.toThrow( 'mocked MLAuth error' ); @@ -100,12 +103,12 @@ describe('DetectionRulesClient.upgradePrebuiltRule', () => { }); it('deletes the old rule ', async () => { - await upgradePrebuiltRule(rulesClient, { ruleAsset }, mlAuthz); + await detectionRulesClient.upgradePrebuiltRule({ ruleAsset }); expect(rulesClient.delete).toHaveBeenCalled(); }); it('creates a new rule with the new type and expected params of the original rules', async () => { - await upgradePrebuiltRule(rulesClient, { ruleAsset }, mlAuthz); + await detectionRulesClient.upgradePrebuiltRule({ ruleAsset }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ @@ -127,7 +130,6 @@ describe('DetectionRulesClient.upgradePrebuiltRule', () => { options: { id: installedRule.id, // id is maintained }, - allowMissingConnectorSecrets: undefined, }) ); }); @@ -151,7 +153,7 @@ describe('DetectionRulesClient.upgradePrebuiltRule', () => { }); it('patches the existing rule with the new params from the rule asset', async () => { - await upgradePrebuiltRule(rulesClient, { ruleAsset }, mlAuthz); + await detectionRulesClient.upgradePrebuiltRule({ ruleAsset }); expect(rulesClient.update).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.ts new file mode 100644 index 0000000000000..b516fc997055c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/upgrade_prebuilt_rule.ts @@ -0,0 +1,90 @@ +/* + * 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 { RulesClient } from '@kbn/alerting-plugin/server'; +import type { PrebuiltRuleAsset } from '../../../prebuilt_rules'; +import type { MlAuthz } from '../../../../machine_learning/authz'; +import type { RuleAlertType, RuleParams } from '../../../rule_schema'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; +import { + convertPatchAPIToInternalSchema, + convertCreateAPIToInternalSchema, +} from '../../normalization/rule_converters'; +import { transformAlertToRuleAction } from '../../../../../../common/detection_engine/transform_actions'; + +import { validateMlAuth, ClientError } from './utils'; + +import { readRules } from './read_rules'; + +export interface UpgradePrebuiltRuleProps { + ruleAsset: PrebuiltRuleAsset; +} + +export const upgradePrebuiltRule = async ( + rulesClient: RulesClient, + upgradePrebuiltRulePayload: UpgradePrebuiltRuleProps, + mlAuthz: MlAuthz +): Promise => + withSecuritySpan('DetectionRulesClient.upgradePrebuiltRule', async () => { + const { ruleAsset } = upgradePrebuiltRulePayload; + + await validateMlAuth(mlAuthz, ruleAsset.type); + + const existingRule = await readRules({ + rulesClient, + ruleId: ruleAsset.rule_id, + id: undefined, + }); + + if (!existingRule) { + throw new ClientError(`Failed to find rule ${ruleAsset.rule_id}`, 500); + } + + if (ruleAsset.type !== existingRule.params.type) { + // If we're trying to change the type of a prepackaged rule, we need to delete the old one + // and replace it with the new rule, keeping the enabled setting, actions, throttle, id, + // and exception lists from the old rule + await rulesClient.delete({ id: existingRule.id }); + + const internalRule = convertCreateAPIToInternalSchema( + { + ...ruleAsset, + enabled: existingRule.enabled, + exceptions_list: existingRule.params.exceptionsList, + actions: existingRule.actions.map(transformAlertToRuleAction), + timeline_id: existingRule.params.timelineId, + timeline_title: existingRule.params.timelineTitle, + }, + { immutable: true, defaultEnabled: existingRule.enabled } + ); + + return rulesClient.create({ + data: internalRule, + options: { id: existingRule.id }, + }); + } + + // Else, simply patch it. + const patchedRule = convertPatchAPIToInternalSchema(ruleAsset, existingRule); + + await rulesClient.update({ + id: existingRule.id, + data: patchedRule, + }); + + const updatedRule = await readRules({ + rulesClient, + ruleId: ruleAsset.rule_id, + id: undefined, + }); + + if (!updatedRule) { + throw new ClientError(`Rule ${ruleAsset.rule_id} not found after upgrade`, 500); + } + + return updatedRule; + }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/utils.ts new file mode 100644 index 0000000000000..0173ba5aea370 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_management/utils.ts @@ -0,0 +1,38 @@ +/* + * 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 { RulesClient } from '@kbn/alerting-plugin/server'; + +import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { MlAuthz } from '../../../../machine_learning/authz'; + +import type { RuleAlertType } from '../../../rule_schema'; +import { throwAuthzError } from '../../../../machine_learning/validation'; + +export const toggleRuleEnabledOnUpdate = async ( + rulesClient: RulesClient, + existingRule: RuleAlertType, + updatedRuleEnabled?: boolean +) => { + if (existingRule.enabled && updatedRuleEnabled === false) { + await rulesClient.disable({ id: existingRule.id }); + } else if (!existingRule.enabled && updatedRuleEnabled === true) { + await rulesClient.enable({ id: existingRule.id }); + } +}; + +export const validateMlAuth = async (mlAuthz: MlAuthz, ruleType: Type) => { + throwAuthzError(await mlAuthz.validateRuleType(ruleType)); +}; + +export class ClientError extends Error { + public readonly statusCode: number; + constructor(message: string, statusCode: number) { + super(message); + this.statusCode = statusCode; + } +} diff --git a/x-pack/plugins/security_solution/server/lib/machine_learning/authz.ts b/x-pack/plugins/security_solution/server/lib/machine_learning/authz.ts index f96866d968e4b..aa880c79393d3 100644 --- a/x-pack/plugins/security_solution/server/lib/machine_learning/authz.ts +++ b/x-pack/plugins/security_solution/server/lib/machine_learning/authz.ts @@ -28,7 +28,7 @@ export interface MlAuthz { * @param ml {@link MlPluginSetup} ML services to fetch ML capabilities * @param request A {@link KibanaRequest} representing the authenticated user * - * @returns A {@link MLAuthz} service object + * @returns A {@link MlAuthz} service object */ export const buildMlAuthz = ({ license, diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts index f2e090b389ff6..a47535772dd83 100644 --- a/x-pack/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/plugins/security_solution/server/request_context_factory.ts @@ -29,6 +29,7 @@ import { RiskEngineDataClient } from './lib/entity_analytics/risk_engine/risk_en import { RiskScoreDataClient } from './lib/entity_analytics/risk_score/risk_score_data_client'; import { AssetCriticalityDataClient } from './lib/entity_analytics/asset_criticality'; import { createDetectionRulesClient } from './lib/detection_engine/rule_management/logic/rule_management/detection_rules_client'; +import { buildMlAuthz } from './lib/machine_learning/authz'; export interface IRequestContextFactory { create( @@ -113,14 +114,19 @@ export class RequestContextFactory implements IRequestContextFactory { getAuditLogger, - getDetectionRulesClient: () => - createDetectionRulesClient( - startPlugins.alerting.getRulesClientWithRequest(request), + getDetectionRulesClient: () => { + const mlAuthz = buildMlAuthz({ + license: licensing.license, + ml: plugins.ml, request, - coreContext.savedObjects.client, - licensing, - plugins.ml - ), + savedObjectsClient: coreContext.savedObjects.client, + }); + + return createDetectionRulesClient( + startPlugins.alerting.getRulesClientWithRequest(request), + mlAuthz + ); + }, getDetectionEngineHealthClient: memoize(() => ruleMonitoringService.createDetectionEngineHealthClient({ From 5f2e0c613a5bef0b30bf4dd3cb05f29405ef19b0 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 6 Jun 2024 09:13:23 -0400 Subject: [PATCH 12/87] [Observability Onboarding] Update links for integration buttons in observability solutions (#184477) ## Summary Continuation of https://github.com/elastic/kibana/pull/184164. Changes the integration links for metrics and logs to link to the new onboarding flow. --- .../infra/public/pages/logs/shared/page_template.tsx | 10 +++++----- .../infra/public/pages/metrics/page_template.tsx | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/shared/page_template.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/shared/page_template.tsx index 31b8718d9c850..c0dfc79641dde 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/shared/page_template.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/shared/page_template.tsx @@ -8,7 +8,7 @@ import React, { useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import type { LazyObservabilityPageTemplateProps } from '@kbn/observability-shared-plugin/public'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { OBSERVABILITY_ONBOARDING_LOCATOR } from '@kbn/deeplinks-observability'; import { NoDataConfig } from '@kbn/shared-ux-page-kibana-template'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; @@ -29,13 +29,13 @@ export const LogsPageTemplate: React.FC = ({ observabilityShared: { navigation: { PageTemplate }, }, + share, docLinks, }, } = useKibanaContextForPlugin(); - const { http } = useKibana().services; - const basePath = http!.basePath.get(); - + const onboardingLocator = share.url.locators.get(OBSERVABILITY_ONBOARDING_LOCATOR); + const href = onboardingLocator?.getRedirectUrl({ category: 'logs' }); const { setScreenContext } = observabilityAIAssistant?.service || {}; useEffect(() => { @@ -79,7 +79,7 @@ export const LogsPageTemplate: React.FC = ({ defaultMessage: 'Use the Elastic Agent or Beats to send logs to Elasticsearch. We make it easy with integrations for many popular systems and apps.', }), - href: basePath + `/app/integrations/browse`, + href, }, }, docsLink: docLinks.links.observability.guide, diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/page_template.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/page_template.tsx index 74128ad8eb41e..d48b77404767d 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/page_template.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/page_template.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { OBSERVABILITY_ONBOARDING_LOCATOR } from '@kbn/deeplinks-observability'; import { i18n } from '@kbn/i18n'; import type { LazyObservabilityPageTemplateProps } from '@kbn/observability-shared-plugin/public'; import type { NoDataConfig } from '@kbn/shared-ux-page-kibana-template'; @@ -30,10 +31,13 @@ export const MetricsPageTemplate: React.FC = observabilityShared: { navigation: { PageTemplate }, }, + share, docLinks, }, } = useKibanaContextForPlugin(); + const onboardingLocator = share.url.locators.get(OBSERVABILITY_ONBOARDING_LOCATOR); + const href = onboardingLocator?.getRedirectUrl({ category: 'infra' }); const { source, error: sourceError, loadSource, isLoading } = useSourceContext(); const { error: dataViewLoadError, refetch: loadDataView } = useMetricsDataViewContext(); const { remoteClustersExist, metricIndicesExist } = source?.status ?? {}; @@ -48,6 +52,7 @@ export const MetricsPageTemplate: React.FC = beats: { title: noMetricIndicesPromptPrimaryActionTitle, description: noMetricIndicesPromptDescription, + href, }, }, docsLink: docLinks.links.observability.guide, From 1c255c611a7caf2c10a126d8424c403e8763de2c Mon Sep 17 00:00:00 2001 From: Rachel Shen Date: Thu, 6 Jun 2024 07:31:24 -0600 Subject: [PATCH 13/87] [Fix] Add isLoading state to Global Search (#183866) ## Summary This is a clean up PR for the global search. This PR keeps the height of the svg until it loads. This PR sets up the `isLoading` prop provided by EUI. --- .../public/components/search_bar.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/global_search_bar/public/components/search_bar.tsx b/x-pack/plugins/global_search_bar/public/components/search_bar.tsx index 04e519a83b534..726c41f399450 100644 --- a/x-pack/plugins/global_search_bar/public/components/search_bar.tsx +++ b/x-pack/plugins/global_search_bar/public/components/search_bar.tsx @@ -71,6 +71,7 @@ export const SearchBar: FC = (opts) => { const [searchableTypes, setSearchableTypes] = useState([]); const [showAppend, setShowAppend] = useState(true); const UNKNOWN_TAG_ID = '__unknown__'; + const [isLoading, setIsLoading] = useState(false); useEffect(() => { if (initialLoad) { @@ -126,7 +127,9 @@ export const SearchBar: FC = (opts) => { searchSubscription.current = null; } + setIsLoading(true); const suggestions = loadSuggestions(searchValue.toLowerCase()); + setIsLoading(false); let aggregatedResults: GlobalSearchResult[] = []; if (searchValue.length !== 0) { @@ -152,7 +155,7 @@ export const SearchBar: FC = (opts) => { // so the SearchOption won't highlight anything if only one call is fired // in practice, this is hard to spot, unlikely to happen, and is a negligible issue setSearchTerm(rawParams.term ?? ''); - + setIsLoading(true); searchSubscription.current = globalSearch.find(searchParams, {}).subscribe({ next: ({ results }) => { if (searchValue.length > 0) { @@ -169,11 +172,14 @@ export const SearchBar: FC = (opts) => { setOptions(aggregatedResults, suggestions, searchParams.tags); }, error: (err) => { + setIsLoading(false); // Not doing anything on error right now because it'll either just show the previous // results or empty results which is basically what we want anyways reportEvent.error({ message: err, searchValue }); }, - complete: () => {}, + complete: () => { + setIsLoading(false); + }, }); } }, @@ -320,6 +326,7 @@ export const SearchBar: FC = (opts) => { return ( Date: Thu, 6 Jun 2024 15:49:41 +0200 Subject: [PATCH 14/87] [OAS] Refactor `description` -> `summary` (#184651) ## Summary Per [the OAS docs](https://swagger.io/specification/), they have an info object with a `summary` and `description` field. This PR refactors the existing router `description` field to to OAS `summary` (that is how it has been used) and introduces a "new" `description` field that will be used for the longer form descriptions. ## Resources * https://swagger.io/specification/ --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: lcawl --- oas_docs/bundle.json | 8 ++---- .../http/core-http-server/src/router/route.ts | 28 ++++++++++++++++++- .../core-http-server/src/versioning/types.ts | 19 +++++++++++-- .../src/routes/status.ts | 2 +- .../__snapshots__/generate_oas.test.ts.snap | 16 ++++++----- .../src/generate_oas.test.util.ts | 5 ++-- .../src/process_router.test.ts | 2 -- .../src/process_router.ts | 4 +-- .../src/process_versioned_router.ts | 3 +- .../http/short_urls/register_create_route.ts | 2 +- .../http/short_urls/register_delete_route.ts | 2 +- .../http/short_urls/register_get_route.ts | 2 +- .../http/short_urls/register_resolve_route.ts | 2 +- .../server/routes/connector/get/get.ts | 2 +- .../routes/connector/get_all/get_all.ts | 2 +- .../routes/connector/list_types/list_types.ts | 2 +- .../plugins/actions/server/routes/create.ts | 2 +- .../plugins/actions/server/routes/delete.ts | 2 +- .../plugins/actions/server/routes/execute.ts | 4 ++- .../actions/server/routes/legacy/create.ts | 2 +- .../actions/server/routes/legacy/delete.ts | 2 +- .../actions/server/routes/legacy/execute.ts | 2 +- .../actions/server/routes/legacy/get.ts | 2 +- .../actions/server/routes/legacy/get_all.ts | 2 +- .../server/routes/legacy/list_action_types.ts | 2 +- .../actions/server/routes/legacy/update.ts | 2 +- .../plugins/actions/server/routes/update.ts | 2 +- .../alerting/server/routes/disable_rule.ts | 2 +- .../alerting/server/routes/enable_rule.ts | 2 +- .../plugins/alerting/server/routes/health.ts | 2 +- .../alerting/server/routes/mute_all_rule.ts | 2 +- .../rule/apis/create/create_rule_route.ts | 2 +- .../rule/apis/delete/delete_rule_route.ts | 2 +- .../routes/rule/apis/find/find_rules_route.ts | 2 +- .../routes/rule/apis/get/get_rule_route.ts | 2 +- .../routes/rule/apis/mute_alert/mute_alert.ts | 2 +- .../rule/apis/update/update_rule_route.ts | 2 +- .../alerting/server/routes/rule_types.ts | 2 +- .../alerting/server/routes/unmute_alert.ts | 2 +- .../alerting/server/routes/unmute_all_rule.ts | 2 +- .../server/routes/update_rule_api_key.ts | 2 +- .../routes/api/cases/alerts/get_cases.ts | 2 +- .../server/routes/api/cases/delete_cases.ts | 2 +- .../server/routes/api/cases/find_cases.ts | 2 +- .../cases/server/routes/api/cases/get_case.ts | 2 +- .../server/routes/api/cases/patch_cases.ts | 2 +- .../server/routes/api/cases/post_case.ts | 2 +- .../server/routes/api/cases/push_case.ts | 2 +- .../api/cases/reporters/get_reporters.ts | 2 +- .../server/routes/api/cases/tags/get_tags.ts | 2 +- .../api/comments/delete_all_comments.ts | 2 +- .../routes/api/comments/delete_comment.ts | 2 +- .../routes/api/comments/find_comments.ts | 2 +- .../server/routes/api/comments/get_alerts.ts | 2 +- .../routes/api/comments/get_all_comment.ts | 2 +- .../server/routes/api/comments/get_comment.ts | 2 +- .../routes/api/comments/patch_comment.ts | 2 +- .../routes/api/comments/post_comment.ts | 2 +- .../routes/api/configure/get_configure.ts | 2 +- .../routes/api/configure/get_connectors.ts | 2 +- .../routes/api/configure/patch_configure.ts | 2 +- .../routes/api/configure/post_configure.ts | 2 +- .../server/routes/api/stats/get_status.ts | 2 +- .../api/user_actions/find_user_actions.ts | 2 +- .../api/user_actions/get_all_user_actions.ts | 2 +- .../plugins/features/server/routes/index.ts | 2 +- .../logstash/server/routes/pipeline/delete.ts | 2 +- .../logstash/server/routes/pipeline/load.ts | 2 +- .../logstash/server/routes/pipeline/save.ts | 2 +- .../server/routes/pipelines/delete.ts | 2 +- .../logstash/server/routes/pipelines/list.ts | 2 +- .../plugins/ml/server/routes/saved_objects.ts | 2 +- .../routes/authorization/roles/delete.ts | 2 +- .../server/routes/authorization/roles/get.ts | 2 +- .../routes/authorization/roles/get_all.ts | 2 +- .../server/routes/authorization/roles/put.ts | 2 +- .../session_management/invalidate.test.ts | 2 +- .../routes/session_management/invalidate.ts | 2 +- .../task_manager/server/routes/health.ts | 2 +- .../reindex_indices/batch_reindex_indices.ts | 4 +-- .../routes/reindex_indices/reindex_indices.ts | 6 ++-- .../upgrade_assistant/server/routes/status.ts | 2 +- 82 files changed, 142 insertions(+), 99 deletions(-) diff --git a/oas_docs/bundle.json b/oas_docs/bundle.json index cdd86729d7f8e..1dfcdd50639b3 100644 --- a/oas_docs/bundle.json +++ b/oas_docs/bundle.json @@ -499,8 +499,7 @@ "description": "Kibana's operational status. A minimal response is sent for unauthorized users." } } - }, - "description": "Get Kibana's current status." + } }, "503": { "content": { @@ -517,11 +516,10 @@ "description": "Kibana's operational status. A minimal response is sent for unauthorized users." } } - }, - "description": "Get Kibana's current status." + } } }, - "summary": "Get Kibana's current status.", + "summary": "Get Kibana's current status", "tags": [] } } diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts index bb3e59cfcd00b..28f889d5dbdef 100644 --- a/packages/core/http/core-http-server/src/router/route.ts +++ b/packages/core/http/core-http-server/src/router/route.ts @@ -160,7 +160,33 @@ export interface RouteConfigOptions { idleSocket?: number; }; - /** A short, human-friendly description of this endpoint */ + /** + * Short summary of this route. Required for all routes used in OAS documentation. + * + * @example + * ```ts + * router.get({ + * path: '/api/foo/{id}', + * access: 'public', + * summary: `Get foo resources for an ID`, + * }) + * ``` + */ + summary?: string; + + /** + * Optional API description, which supports [CommonMark](https://spec.commonmark.org) markdown formatting + * + * @example + * ```ts + * router.get({ + * path: '/api/foo/{id}', + * access: 'public', + * summary: `Get foo resources for an ID`, + * description: `Foo resources require **X** and **Y** `read` permissions to access.`, + * }) + * ``` + */ description?: string; } diff --git a/packages/core/http/core-http-server/src/versioning/types.ts b/packages/core/http/core-http-server/src/versioning/types.ts index 8495f05210a36..af3173691415f 100644 --- a/packages/core/http/core-http-server/src/versioning/types.ts +++ b/packages/core/http/core-http-server/src/versioning/types.ts @@ -55,14 +55,29 @@ export type VersionedRouteConfig = Omit< enableQueryVersion?: boolean; /** - * Human-friendly description of this route, should be usable for documentation + * Short summary of this route. Required for all routes used in OAS documentation. * * @example * ```ts * router.get({ * path: '/api/foo/{id}', * access: 'public', - * description: `Retrieve foo resources given an ID. To retrieve a list of IDs use the GET /api/foo API.`, + * summary: `Get foo resources for an ID`, + * }) + * ``` + */ + summary?: string; + + /** + * Optional API description, which supports [CommonMark](https://spec.commonmark.org) markdown formatting + * + * @example + * ```ts + * router.get({ + * path: '/api/foo/{id}', + * access: 'public', + * summary: `Get foo resources for an ID`, + * description: `Foo resources require **X** and **Y** `read` permissions to access.`, * }) * ``` */ diff --git a/packages/core/status/core-status-server-internal/src/routes/status.ts b/packages/core/status/core-status-server-internal/src/routes/status.ts index 5557a4d60aaef..4b243240321d7 100644 --- a/packages/core/status/core-status-server-internal/src/routes/status.ts +++ b/packages/core/status/core-status-server-internal/src/routes/status.ts @@ -88,7 +88,7 @@ export const registerStatusRoute = ({ // ROUTE_TAG_ACCEPT_JWT from '@kbn/security-plugin/server' that cannot be imported here directly. tags: ['api', 'security:acceptJWT'], access: 'public', // needs to be public to allow access from "system" users like k8s readiness probes. - description: `Get Kibana's current status.`, + summary: `Get Kibana's current status`, }, validate: { request: { diff --git a/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap b/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap index 2c6186ff56984..fee1a8534a7ec 100644 --- a/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap +++ b/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap @@ -26,6 +26,7 @@ Object { "paths": Object { "/foo/{id}": Object { "get": Object { + "description": undefined, "operationId": "/foo/{id}#0", "parameters": Array [ Object { @@ -85,7 +86,6 @@ Object { }, }, }, - "description": "No description", }, }, "summary": "", @@ -133,6 +133,7 @@ Object { "paths": Object { "/bar": Object { "get": Object { + "description": undefined, "operationId": "/bar#0", "parameters": Array [ Object { @@ -221,6 +222,7 @@ Object { }, "/foo/{id}/{path*}": Object { "get": Object { + "description": "route description", "operationId": "/foo/{id}/{path*}#0", "parameters": Array [ Object { @@ -357,15 +359,15 @@ Object { }, }, }, - "description": "route", }, }, - "summary": "route", + "summary": "route summary", "tags": Array [ "bar", ], }, "post": Object { + "description": "route description", "operationId": "/foo/{id}/{path*}#1", "parameters": Array [ Object { @@ -502,10 +504,9 @@ Object { }, }, }, - "description": "route", }, }, - "summary": "route", + "summary": "route summary", "tags": Array [ "bar", ], @@ -576,6 +577,7 @@ Object { "paths": Object { "/recursive": Object { "get": Object { + "description": undefined, "operationId": "/recursive#0", "parameters": Array [ Object { @@ -611,7 +613,6 @@ Object { }, }, }, - "description": "No description", }, }, "summary": "", @@ -659,6 +660,7 @@ Object { "paths": Object { "/foo/{id}": Object { "get": Object { + "description": undefined, "operationId": "/foo/{id}#0", "parameters": Array [ Object { @@ -688,7 +690,6 @@ Object { "schema": Object {}, }, }, - "description": "No description", }, }, "summary": "", @@ -697,6 +698,7 @@ Object { }, "/test": Object { "get": Object { + "description": undefined, "operationId": "/test#0", "parameters": Array [ Object { diff --git a/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts b/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts index b4e273b3a5b7b..bed7d10c51d8e 100644 --- a/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts +++ b/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts @@ -55,7 +55,8 @@ export const getRouterDefaults = () => ({ method: 'get', options: { tags: ['foo', 'oas-tag:bar'], - description: 'route', + summary: 'route summary', + description: 'route description', }, validationSchemas: { request: { @@ -82,7 +83,7 @@ export const getVersionedRouterDefaults = () => ({ method: 'get', path: '/bar', options: { - description: 'versioned route', + summary: 'versioned route', access: 'public', options: { tags: ['ignore-me', 'oas-tag:versioned'], diff --git a/packages/kbn-router-to-openapispec/src/process_router.test.ts b/packages/kbn-router-to-openapispec/src/process_router.test.ts index 32888cfe1dd47..41850b31c5d46 100644 --- a/packages/kbn-router-to-openapispec/src/process_router.test.ts +++ b/packages/kbn-router-to-openapispec/src/process_router.test.ts @@ -45,7 +45,6 @@ describe('extractResponses', () => { }; expect(extractResponses(route, oasConverter)).toEqual({ 200: { - description: 'No description', content: { 'application/test+json; Elastic-Api-Version=2023-10-31': { schema: { @@ -60,7 +59,6 @@ describe('extractResponses', () => { }, }, 404: { - description: 'No description', content: { 'application/test2+json; Elastic-Api-Version=2023-10-31': { schema: { diff --git a/packages/kbn-router-to-openapispec/src/process_router.ts b/packages/kbn-router-to-openapispec/src/process_router.ts index ce9486b140dc4..393b745b6aab3 100644 --- a/packages/kbn-router-to-openapispec/src/process_router.ts +++ b/packages/kbn-router-to-openapispec/src/process_router.ts @@ -60,7 +60,8 @@ export const processRouter = ( } const operation: OpenAPIV3.OperationObject = { - summary: route.options.description ?? '', + summary: route.options.summary ?? '', + description: route.options.description, tags: route.options.tags ? extractTags(route.options.tags) : [], requestBody: !!validationSchemas?.body ? { @@ -103,7 +104,6 @@ export const extractResponses = (route: InternalRouterRoute, converter: OasConve const oasSchema = converter.convert(schema.body()); acc[statusCode] = { ...acc[statusCode], - description: route.options.description ?? 'No description', content: { ...((acc[statusCode] ?? {}) as OpenAPIV3.ResponseObject).content, [getVersionedContentTypeString( diff --git a/packages/kbn-router-to-openapispec/src/process_versioned_router.ts b/packages/kbn-router-to-openapispec/src/process_versioned_router.ts index 85246a5164306..cc873b26835cf 100644 --- a/packages/kbn-router-to-openapispec/src/process_versioned_router.ts +++ b/packages/kbn-router-to-openapispec/src/process_versioned_router.ts @@ -84,7 +84,8 @@ export const processVersionedRouter = ( const contentType = extractContentType(route.options.options?.body); const hasVersionFilter = Boolean(filters?.version); const operation: OpenAPIV3.OperationObject = { - summary: route.options.description ?? '', + summary: route.options.summary ?? '', + description: route.options.description, tags: route.options.options?.tags ? extractTags(route.options.options.tags) : [], requestBody: hasBody ? { diff --git a/src/plugins/share/server/url_service/http/short_urls/register_create_route.ts b/src/plugins/share/server/url_service/http/short_urls/register_create_route.ts index 0848fdfbfe605..3b8667d92cfb2 100644 --- a/src/plugins/share/server/url_service/http/short_urls/register_create_route.ts +++ b/src/plugins/share/server/url_service/http/short_urls/register_create_route.ts @@ -17,7 +17,7 @@ export const registerCreateRoute = (router: IRouter, url: ServerUrlService) => { path: '/api/short_url', options: { access: 'public', - description: `Create a short URL`, + summary: `Create a short URL`, }, validate: { body: schema.object({ diff --git a/src/plugins/share/server/url_service/http/short_urls/register_delete_route.ts b/src/plugins/share/server/url_service/http/short_urls/register_delete_route.ts index 258faff0d04a6..2df23f190c2d7 100644 --- a/src/plugins/share/server/url_service/http/short_urls/register_delete_route.ts +++ b/src/plugins/share/server/url_service/http/short_urls/register_delete_route.ts @@ -16,7 +16,7 @@ export const registerDeleteRoute = (router: IRouter, url: ServerUrlService) => { path: '/api/short_url/{id}', options: { access: 'public', - description: `Delete a short URL`, + summary: `Delete a short URL`, }, validate: { params: schema.object({ diff --git a/src/plugins/share/server/url_service/http/short_urls/register_get_route.ts b/src/plugins/share/server/url_service/http/short_urls/register_get_route.ts index ae108ccd11d97..8c7df947d4662 100644 --- a/src/plugins/share/server/url_service/http/short_urls/register_get_route.ts +++ b/src/plugins/share/server/url_service/http/short_urls/register_get_route.ts @@ -16,7 +16,7 @@ export const registerGetRoute = (router: IRouter, url: ServerUrlService) => { path: '/api/short_url/{id}', options: { access: 'public', - description: `Get a short URL`, + summary: `Get a short URL`, }, validate: { params: schema.object({ diff --git a/src/plugins/share/server/url_service/http/short_urls/register_resolve_route.ts b/src/plugins/share/server/url_service/http/short_urls/register_resolve_route.ts index 6076889945f36..e37f2c818dca8 100644 --- a/src/plugins/share/server/url_service/http/short_urls/register_resolve_route.ts +++ b/src/plugins/share/server/url_service/http/short_urls/register_resolve_route.ts @@ -17,7 +17,7 @@ export const registerResolveRoute = (router: IRouter, url: ServerUrlService) => path: '/api/short_url/_slug/{slug}', options: { access: 'public', - description: `Resolve a short URL`, + summary: `Resolve a short URL`, }, validate: { params: schema.object({ diff --git a/x-pack/plugins/actions/server/routes/connector/get/get.ts b/x-pack/plugins/actions/server/routes/connector/get/get.ts index 2a05405a6a722..bb15a2e2e5cf5 100644 --- a/x-pack/plugins/actions/server/routes/connector/get/get.ts +++ b/x-pack/plugins/actions/server/routes/connector/get/get.ts @@ -25,7 +25,7 @@ export const getConnectorRoute = ( path: `${BASE_ACTION_API_PATH}/connector/{id}`, options: { access: 'public', - description: `Get connector information`, + summary: `Get connector information`, }, validate: { params: getConnectorParamsSchemaV1, diff --git a/x-pack/plugins/actions/server/routes/connector/get_all/get_all.ts b/x-pack/plugins/actions/server/routes/connector/get_all/get_all.ts index e37edc2347a32..b5ffb4499b073 100644 --- a/x-pack/plugins/actions/server/routes/connector/get_all/get_all.ts +++ b/x-pack/plugins/actions/server/routes/connector/get_all/get_all.ts @@ -22,7 +22,7 @@ export const getAllConnectorsRoute = ( path: `${BASE_ACTION_API_PATH}/connectors`, options: { access: 'public', - description: `Get all connectors`, + summary: `Get all connectors`, }, validate: {}, }, diff --git a/x-pack/plugins/actions/server/routes/connector/list_types/list_types.ts b/x-pack/plugins/actions/server/routes/connector/list_types/list_types.ts index e09a828c9ff6c..4632a6fb9e83e 100644 --- a/x-pack/plugins/actions/server/routes/connector/list_types/list_types.ts +++ b/x-pack/plugins/actions/server/routes/connector/list_types/list_types.ts @@ -26,7 +26,7 @@ export const listTypesRoute = ( path: `${BASE_ACTION_API_PATH}/connector_types`, options: { access: 'public', - description: `Get connector types`, + summary: `Get connector types`, }, validate: { query: connectorTypesQuerySchemaV1, diff --git a/x-pack/plugins/actions/server/routes/create.ts b/x-pack/plugins/actions/server/routes/create.ts index 63cf948d318cd..a18cf4c61ef2c 100644 --- a/x-pack/plugins/actions/server/routes/create.ts +++ b/x-pack/plugins/actions/server/routes/create.ts @@ -55,7 +55,7 @@ export const createActionRoute = ( path: `${BASE_ACTION_API_PATH}/connector/{id?}`, options: { access: 'public', - description: 'Create a connector', + summary: 'Create a connector', }, validate: { params: schema.maybe( diff --git a/x-pack/plugins/actions/server/routes/delete.ts b/x-pack/plugins/actions/server/routes/delete.ts index c6a6c8afcbb72..950a3a8a60b17 100644 --- a/x-pack/plugins/actions/server/routes/delete.ts +++ b/x-pack/plugins/actions/server/routes/delete.ts @@ -25,7 +25,7 @@ export const deleteActionRoute = ( path: `${BASE_ACTION_API_PATH}/connector/{id}`, options: { access: 'public', - description: `Delete a connector`, + summary: `Delete a connector`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/actions/server/routes/execute.ts b/x-pack/plugins/actions/server/routes/execute.ts index d366feb7ce3ee..8b022e4d13f2c 100644 --- a/x-pack/plugins/actions/server/routes/execute.ts +++ b/x-pack/plugins/actions/server/routes/execute.ts @@ -41,7 +41,9 @@ export const executeActionRoute = ( path: `${BASE_ACTION_API_PATH}/connector/{id}/_execute`, options: { access: 'public', - description: `Run a connector`, + summary: `Run a connector`, + description: + 'You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. If you use an index connector, you must also have `all`, `create`, `index`, or `write` indices privileges.', }, validate: { body: bodySchema, diff --git a/x-pack/plugins/actions/server/routes/legacy/create.ts b/x-pack/plugins/actions/server/routes/legacy/create.ts index bbdf528f21564..d4a7da1420f7f 100644 --- a/x-pack/plugins/actions/server/routes/legacy/create.ts +++ b/x-pack/plugins/actions/server/routes/legacy/create.ts @@ -31,7 +31,7 @@ export const createActionRoute = ( path: `${BASE_ACTION_API_PATH}/action`, options: { access: 'public', - description: `Create a connector`, + summary: `Create a connector`, }, validate: { body: bodySchema, diff --git a/x-pack/plugins/actions/server/routes/legacy/delete.ts b/x-pack/plugins/actions/server/routes/legacy/delete.ts index 57c4346084f57..0639019f73278 100644 --- a/x-pack/plugins/actions/server/routes/legacy/delete.ts +++ b/x-pack/plugins/actions/server/routes/legacy/delete.ts @@ -27,7 +27,7 @@ export const deleteActionRoute = ( path: `${BASE_ACTION_API_PATH}/action/{id}`, options: { access: 'public', - description: `Delete a connector`, + summary: `Delete a connector`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/actions/server/routes/legacy/execute.ts b/x-pack/plugins/actions/server/routes/legacy/execute.ts index f4ec794635263..ecf036617a28a 100644 --- a/x-pack/plugins/actions/server/routes/legacy/execute.ts +++ b/x-pack/plugins/actions/server/routes/legacy/execute.ts @@ -33,7 +33,7 @@ export const executeActionRoute = ( path: `${BASE_ACTION_API_PATH}/action/{id}/_execute`, options: { access: 'public', - description: `Run a connector`, + summary: `Run a connector`, }, validate: { body: bodySchema, diff --git a/x-pack/plugins/actions/server/routes/legacy/get.ts b/x-pack/plugins/actions/server/routes/legacy/get.ts index d47efc698c2fe..4c8d797205238 100644 --- a/x-pack/plugins/actions/server/routes/legacy/get.ts +++ b/x-pack/plugins/actions/server/routes/legacy/get.ts @@ -27,7 +27,7 @@ export const getActionRoute = ( path: `${BASE_ACTION_API_PATH}/action/{id}`, options: { access: 'public', - description: `Get connector information`, + summary: `Get connector information`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/actions/server/routes/legacy/get_all.ts b/x-pack/plugins/actions/server/routes/legacy/get_all.ts index 19fc32389c2ec..2ecd570cb3e76 100644 --- a/x-pack/plugins/actions/server/routes/legacy/get_all.ts +++ b/x-pack/plugins/actions/server/routes/legacy/get_all.ts @@ -22,7 +22,7 @@ export const getAllActionRoute = ( path: `${BASE_ACTION_API_PATH}`, options: { access: 'public', - description: `Get all connectors`, + summary: `Get all connectors`, }, validate: {}, }, diff --git a/x-pack/plugins/actions/server/routes/legacy/list_action_types.ts b/x-pack/plugins/actions/server/routes/legacy/list_action_types.ts index ef587d1ad11a6..fac078843e02d 100644 --- a/x-pack/plugins/actions/server/routes/legacy/list_action_types.ts +++ b/x-pack/plugins/actions/server/routes/legacy/list_action_types.ts @@ -26,7 +26,7 @@ export const listActionTypesRoute = ( path: `${BASE_ACTION_API_PATH}/list_action_types`, options: { access: 'public', - description: `Get connector types`, + summary: `Get connector types`, }, validate: {}, }, diff --git a/x-pack/plugins/actions/server/routes/legacy/update.ts b/x-pack/plugins/actions/server/routes/legacy/update.ts index 0959398dd1a69..59258434050e1 100644 --- a/x-pack/plugins/actions/server/routes/legacy/update.ts +++ b/x-pack/plugins/actions/server/routes/legacy/update.ts @@ -33,7 +33,7 @@ export const updateActionRoute = ( path: `${BASE_ACTION_API_PATH}/action/{id}`, options: { access: 'public', - description: `Update a connector`, + summary: `Update a connector`, }, validate: { body: bodySchema, diff --git a/x-pack/plugins/actions/server/routes/update.ts b/x-pack/plugins/actions/server/routes/update.ts index 68c7a8e9f9def..426deeb19aae3 100644 --- a/x-pack/plugins/actions/server/routes/update.ts +++ b/x-pack/plugins/actions/server/routes/update.ts @@ -51,7 +51,7 @@ export const updateActionRoute = ( path: `${BASE_ACTION_API_PATH}/connector/{id}`, options: { access: 'public', - description: `Update a connector`, + summary: `Update a connector`, }, validate: { body: bodySchema, diff --git a/x-pack/plugins/alerting/server/routes/disable_rule.ts b/x-pack/plugins/alerting/server/routes/disable_rule.ts index 6be1254fb9342..2b60cdbeedeaf 100644 --- a/x-pack/plugins/alerting/server/routes/disable_rule.ts +++ b/x-pack/plugins/alerting/server/routes/disable_rule.ts @@ -32,7 +32,7 @@ export const disableRuleRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{id}/_disable`, options: { access: 'public', - description: `Disable a rule`, + summary: `Disable a rule`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/alerting/server/routes/enable_rule.ts b/x-pack/plugins/alerting/server/routes/enable_rule.ts index 76c96fecaef5a..a6334a25138dc 100644 --- a/x-pack/plugins/alerting/server/routes/enable_rule.ts +++ b/x-pack/plugins/alerting/server/routes/enable_rule.ts @@ -24,7 +24,7 @@ export const enableRuleRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{id}/_enable`, options: { access: 'public', - description: `Enable a rule`, + summary: `Enable a rule`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/alerting/server/routes/health.ts b/x-pack/plugins/alerting/server/routes/health.ts index 5272876773b69..6d178e7bd186c 100644 --- a/x-pack/plugins/alerting/server/routes/health.ts +++ b/x-pack/plugins/alerting/server/routes/health.ts @@ -42,7 +42,7 @@ export const healthRoute = ( path: `${BASE_ALERTING_API_PATH}/_health`, options: { access: 'public', - description: `Get the health of the alerting framework`, + summary: `Get the health of the alerting framework`, }, validate: false, }, diff --git a/x-pack/plugins/alerting/server/routes/mute_all_rule.ts b/x-pack/plugins/alerting/server/routes/mute_all_rule.ts index ca1f31bae3cb2..185d44b95a50e 100644 --- a/x-pack/plugins/alerting/server/routes/mute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/mute_all_rule.ts @@ -27,7 +27,7 @@ export const muteAllRuleRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{id}/_mute_all`, options: { access: 'public', - description: `Mute all alerts`, + summary: `Mute all alerts`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts index 7299da7e8dd39..5bb1eec92de26 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts @@ -34,7 +34,7 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt path: `${BASE_ALERTING_API_PATH}/rule/{id?}`, options: { access: 'public', - description: `Create a rule`, + summary: `Create a rule`, }, validate: { body: createBodySchemaV1, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts index bb862e3a7e5c9..3fe896cec9622 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts @@ -23,7 +23,7 @@ export const deleteRuleRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{id}`, options: { access: 'public', - description: `Delete a rule`, + summary: `Delete a rule`, }, validate: { params: deleteRuleRequestParamsSchemaV1, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts index ac2aa49956b3a..1cadb35969944 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts @@ -43,7 +43,7 @@ const buildFindRulesRoute = ({ path, options: { access: 'public', - description: `Get rules`, + summary: `Get rules`, }, validate: { query: findRulesRequestQuerySchemaV1, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts index 2764163641a97..e08c81a1d2e5c 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts @@ -78,7 +78,7 @@ export const getRuleRoute = ( router, options: { access: 'public', - description: `Get rule details`, + summary: `Get rule details`, }, }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts b/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts index 2e7747f53b1b4..91a254be09663 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts @@ -23,7 +23,7 @@ export const muteAlertRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{rule_id}/alert/{alert_id}/_mute`, options: { access: 'public', - description: `Mute an alert`, + summary: `Mute an alert`, }, validate: { params: muteAlertParamsSchemaV1, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts index 0edaf62ea7ddd..f13d3ac9ee31b 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts @@ -33,7 +33,7 @@ export const updateRuleRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{id}`, options: { access: 'public', - description: `Update a rule`, + summary: `Update a rule`, }, validate: { body: updateBodySchemaV1, diff --git a/x-pack/plugins/alerting/server/routes/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule_types.ts index 5c20fc6df7d5d..1021b4c9a1431 100644 --- a/x-pack/plugins/alerting/server/routes/rule_types.ts +++ b/x-pack/plugins/alerting/server/routes/rule_types.ts @@ -57,7 +57,7 @@ export const ruleTypesRoute = ( path: `${BASE_ALERTING_API_PATH}/rule_types`, options: { access: 'public', - description: `Get rule types`, + summary: `Get rule types`, }, validate: {}, }, diff --git a/x-pack/plugins/alerting/server/routes/unmute_alert.ts b/x-pack/plugins/alerting/server/routes/unmute_alert.ts index 089f63911a902..b0d124e0d3945 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_alert.ts +++ b/x-pack/plugins/alerting/server/routes/unmute_alert.ts @@ -34,7 +34,7 @@ export const unmuteAlertRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{rule_id}/alert/{alert_id}/_unmute`, options: { access: 'public', - description: `Unmute an alert`, + summary: `Unmute an alert`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts b/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts index 247f6377e4ad1..033f5b276828a 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts @@ -24,7 +24,7 @@ export const unmuteAllRuleRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{id}/_unmute_all`, options: { access: 'public', - description: `Unmute all alerts`, + summary: `Unmute all alerts`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts b/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts index 2838e206c92d7..8591f273eeeb3 100644 --- a/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts +++ b/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts @@ -24,7 +24,7 @@ export const updateRuleApiKeyRoute = ( path: `${BASE_ALERTING_API_PATH}/rule/{id}/_update_api_key`, options: { access: 'public', - description: `Update the API key for a rule`, + summary: `Update the API key for a rule`, }, validate: { params: paramSchema, diff --git a/x-pack/plugins/cases/server/routes/api/cases/alerts/get_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/alerts/get_cases.ts index 6371b6ad546cd..e82c93039b2bc 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/alerts/get_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/alerts/get_cases.ts @@ -21,7 +21,7 @@ export const getCasesByAlertIdRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Get cases for an alert`, + summary: `Get cases for an alert`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/cases/delete_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/delete_cases.ts index f36c13499aa70..a9b05c92e0f3d 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/delete_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/delete_cases.ts @@ -16,7 +16,7 @@ export const deleteCaseRoute = createCasesRoute({ path: CASES_URL, routerOptions: { access: 'public', - description: `Delete cases`, + summary: `Delete cases`, }, params: { query: schema.object({ diff --git a/x-pack/plugins/cases/server/routes/api/cases/find_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/find_cases.ts index cfb5a7572894e..070bb4f125725 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/find_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/find_cases.ts @@ -15,7 +15,7 @@ export const findCaseRoute = createCasesRoute({ path: `${CASES_URL}/_find`, routerOptions: { access: 'public', - description: `Search cases`, + summary: `Search cases`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/cases/get_case.ts b/x-pack/plugins/cases/server/routes/api/cases/get_case.ts index c2522df7ddad7..b7557359b005e 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/get_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/get_case.ts @@ -32,7 +32,7 @@ export const getCaseRoute = createCasesRoute({ params, routerOptions: { access: 'public', - description: `Get a case`, + summary: `Get a case`, }, handler: async ({ context, request, response, logger, kibanaVersion }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/cases/patch_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/patch_cases.ts index 2ae12fba4111c..9a01378d0a86c 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/patch_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/patch_cases.ts @@ -16,7 +16,7 @@ export const patchCaseRoute = createCasesRoute({ path: CASES_URL, routerOptions: { access: 'public', - description: `Update cases`, + summary: `Update cases`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/cases/post_case.ts b/x-pack/plugins/cases/server/routes/api/cases/post_case.ts index 5a65ed0851e91..f72819bf7536d 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/post_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/post_case.ts @@ -16,7 +16,7 @@ export const postCaseRoute = createCasesRoute({ path: CASES_URL, routerOptions: { access: 'public', - description: `Create a case`, + summary: `Create a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/cases/push_case.ts b/x-pack/plugins/cases/server/routes/api/cases/push_case.ts index d439b3f03dd79..2933a383aa13d 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/push_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/push_case.ts @@ -18,7 +18,7 @@ export const pushCaseRoute: CaseRoute = createCasesRoute({ path: CASE_PUSH_URL, routerOptions: { access: 'public', - description: `Push a case to an external service`, + summary: `Push a case to an external service`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/cases/reporters/get_reporters.ts b/x-pack/plugins/cases/server/routes/api/cases/reporters/get_reporters.ts index 06ab468d9ce17..9945b5ffa13bf 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/reporters/get_reporters.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/reporters/get_reporters.ts @@ -15,7 +15,7 @@ export const getReportersRoute = createCasesRoute({ path: CASE_REPORTERS_URL, routerOptions: { access: 'public', - description: `Get all case creators`, + summary: `Get all case creators`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/cases/tags/get_tags.ts b/x-pack/plugins/cases/server/routes/api/cases/tags/get_tags.ts index 366ba114c9d4e..1d34fb3e566b1 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/tags/get_tags.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/tags/get_tags.ts @@ -15,7 +15,7 @@ export const getTagsRoute = createCasesRoute({ path: CASE_TAGS_URL, routerOptions: { access: 'public', - description: `Get case tags`, + summary: `Get case tags`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/comments/delete_all_comments.ts b/x-pack/plugins/cases/server/routes/api/comments/delete_all_comments.ts index c395f68fbb147..499b102dbed73 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/delete_all_comments.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/delete_all_comments.ts @@ -15,7 +15,7 @@ export const deleteAllCommentsRoute = createCasesRoute({ path: CASE_COMMENTS_URL, routerOptions: { access: 'public', - description: `Delete all alerts and comments from a case`, + summary: `Delete all alerts and comments from a case`, }, params: { params: schema.object({ diff --git a/x-pack/plugins/cases/server/routes/api/comments/delete_comment.ts b/x-pack/plugins/cases/server/routes/api/comments/delete_comment.ts index 47b9ad9992717..2d0e30bf49eca 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/delete_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/delete_comment.ts @@ -22,7 +22,7 @@ export const deleteCommentRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Delete an alert or comment from a case`, + summary: `Delete an alert or comment from a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/comments/find_comments.ts b/x-pack/plugins/cases/server/routes/api/comments/find_comments.ts index e5f18ba07610f..d44deffc1a9ae 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/find_comments.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/find_comments.ts @@ -22,7 +22,7 @@ export const findCommentsRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Get all alerts and comments for a case`, + summary: `Get all alerts and comments for a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/comments/get_alerts.ts b/x-pack/plugins/cases/server/routes/api/comments/get_alerts.ts index bab7cd8971572..4de1d4690f3b3 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/get_alerts.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/get_alerts.ts @@ -22,7 +22,7 @@ export const getAllAlertsAttachedToCaseRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Get all alerts for a case`, + summary: `Get all alerts for a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts index a070c79541e1c..10f6b072636aa 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts @@ -28,7 +28,7 @@ export const getAllCommentsRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Gets all comments for a case`, + summary: `Gets all comments for a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/comments/get_comment.ts b/x-pack/plugins/cases/server/routes/api/comments/get_comment.ts index e2f5968b66814..69382492ff40b 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/get_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/get_comment.ts @@ -23,7 +23,7 @@ export const getCommentRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Get an alert or comment for a case`, + summary: `Get an alert or comment for a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/comments/patch_comment.ts b/x-pack/plugins/cases/server/routes/api/comments/patch_comment.ts index 03fe0747f83df..ecd4bc6454e55 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/patch_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/patch_comment.ts @@ -23,7 +23,7 @@ export const patchCommentRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Update an alert or comment in a case`, + summary: `Update an alert or comment in a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/comments/post_comment.ts b/x-pack/plugins/cases/server/routes/api/comments/post_comment.ts index d2cbd96b880b9..8128439b74672 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/post_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/post_comment.ts @@ -22,7 +22,7 @@ export const postCommentRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Add an alert or comment to a case`, + summary: `Add an alert or comment to a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/configure/get_configure.ts b/x-pack/plugins/cases/server/routes/api/configure/get_configure.ts index fe5c65dd54ffa..e4d2c75689cd2 100644 --- a/x-pack/plugins/cases/server/routes/api/configure/get_configure.ts +++ b/x-pack/plugins/cases/server/routes/api/configure/get_configure.ts @@ -15,7 +15,7 @@ export const getCaseConfigureRoute = createCasesRoute({ path: CASE_CONFIGURE_URL, routerOptions: { access: 'public', - description: `Get case settings`, + summary: `Get case settings`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/configure/get_connectors.ts b/x-pack/plugins/cases/server/routes/api/configure/get_connectors.ts index 53bc6d958115e..3201cb7005fb4 100644 --- a/x-pack/plugins/cases/server/routes/api/configure/get_connectors.ts +++ b/x-pack/plugins/cases/server/routes/api/configure/get_connectors.ts @@ -18,7 +18,7 @@ export const getConnectorsRoute = createCasesRoute({ routerOptions: { tags: ['access:casesGetConnectorsConfigure'], access: 'public', - description: `Get case connectors`, + summary: `Get case connectors`, }, handler: async ({ context, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/configure/patch_configure.ts b/x-pack/plugins/cases/server/routes/api/configure/patch_configure.ts index dabc73325f286..c028013332866 100644 --- a/x-pack/plugins/cases/server/routes/api/configure/patch_configure.ts +++ b/x-pack/plugins/cases/server/routes/api/configure/patch_configure.ts @@ -17,7 +17,7 @@ export const patchCaseConfigureRoute = createCasesRoute({ path: CASE_CONFIGURE_DETAILS_URL, routerOptions: { access: 'public', - description: `Update case settings`, + summary: `Update case settings`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/configure/post_configure.ts b/x-pack/plugins/cases/server/routes/api/configure/post_configure.ts index cf23dad956d16..6b6d6b1e48441 100644 --- a/x-pack/plugins/cases/server/routes/api/configure/post_configure.ts +++ b/x-pack/plugins/cases/server/routes/api/configure/post_configure.ts @@ -17,7 +17,7 @@ export const postCaseConfigureRoute = createCasesRoute({ path: CASE_CONFIGURE_URL, routerOptions: { access: 'public', - description: `Add case settings`, + summary: `Add case settings`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/stats/get_status.ts b/x-pack/plugins/cases/server/routes/api/stats/get_status.ts index 5a39b2ce6eadc..1db0220365a02 100644 --- a/x-pack/plugins/cases/server/routes/api/stats/get_status.ts +++ b/x-pack/plugins/cases/server/routes/api/stats/get_status.ts @@ -21,7 +21,7 @@ export const getStatusRoute: CaseRoute = createCasesRoute({ options: { deprecated: true }, routerOptions: { access: 'public', - description: `Get case status summary`, + summary: `Get case status summary`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/user_actions/find_user_actions.ts b/x-pack/plugins/cases/server/routes/api/user_actions/find_user_actions.ts index bf43cdef22b4e..0a6c818cffa8b 100644 --- a/x-pack/plugins/cases/server/routes/api/user_actions/find_user_actions.ts +++ b/x-pack/plugins/cases/server/routes/api/user_actions/find_user_actions.ts @@ -22,7 +22,7 @@ export const findUserActionsRoute = createCasesRoute({ }, routerOptions: { access: 'public', - description: `Get user activity for a case`, + summary: `Get user activity for a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts index 7f42a340cd8be..e69e7197c1ece 100644 --- a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts +++ b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts @@ -26,7 +26,7 @@ export const getUserActionsRoute = createCasesRoute({ options: { deprecated: true }, routerOptions: { access: 'public', - description: `Get all user activity for a case`, + summary: `Get all user activity for a case`, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/features/server/routes/index.ts b/x-pack/plugins/features/server/routes/index.ts index 621bf4a4b0e87..97273776df652 100644 --- a/x-pack/plugins/features/server/routes/index.ts +++ b/x-pack/plugins/features/server/routes/index.ts @@ -24,7 +24,7 @@ export function defineRoutes({ router, featureRegistry }: RouteDefinitionParams) options: { tags: ['access:features'], access: 'public', - description: `Get features`, + summary: `Get features`, }, validate: { query: schema.object({ ignoreValidLicenses: schema.boolean({ defaultValue: false }) }), diff --git a/x-pack/plugins/logstash/server/routes/pipeline/delete.ts b/x-pack/plugins/logstash/server/routes/pipeline/delete.ts index 83c6124b49e14..17de5261dc4b7 100644 --- a/x-pack/plugins/logstash/server/routes/pipeline/delete.ts +++ b/x-pack/plugins/logstash/server/routes/pipeline/delete.ts @@ -16,7 +16,7 @@ export function registerPipelineDeleteRoute(router: LogstashPluginRouter) { path: '/api/logstash/pipeline/{id}', options: { access: 'public', - description: `Delete a managed Logstash pipeline`, + summary: `Delete a managed Logstash pipeline`, }, validate: { params: schema.object({ diff --git a/x-pack/plugins/logstash/server/routes/pipeline/load.ts b/x-pack/plugins/logstash/server/routes/pipeline/load.ts index 33775866ccdec..cde032799b3f5 100644 --- a/x-pack/plugins/logstash/server/routes/pipeline/load.ts +++ b/x-pack/plugins/logstash/server/routes/pipeline/load.ts @@ -18,7 +18,7 @@ export function registerPipelineLoadRoute(router: LogstashPluginRouter) { path: '/api/logstash/pipeline/{id}', options: { access: 'public', - description: `Get a managed Logstash pipeline`, + summary: `Get a managed Logstash pipeline`, }, validate: { params: schema.object({ diff --git a/x-pack/plugins/logstash/server/routes/pipeline/save.ts b/x-pack/plugins/logstash/server/routes/pipeline/save.ts index c40bee2630c73..9e837bf9bd416 100644 --- a/x-pack/plugins/logstash/server/routes/pipeline/save.ts +++ b/x-pack/plugins/logstash/server/routes/pipeline/save.ts @@ -23,7 +23,7 @@ export function registerPipelineSaveRoute( path: '/api/logstash/pipeline/{id}', options: { access: 'public', - description: `Create a managed Logstash pipeline`, + summary: `Create a managed Logstash pipeline`, }, validate: { params: schema.object({ diff --git a/x-pack/plugins/logstash/server/routes/pipelines/delete.ts b/x-pack/plugins/logstash/server/routes/pipelines/delete.ts index f6d3d795cdee6..edf235a7357b0 100644 --- a/x-pack/plugins/logstash/server/routes/pipelines/delete.ts +++ b/x-pack/plugins/logstash/server/routes/pipelines/delete.ts @@ -37,7 +37,7 @@ export function registerPipelinesDeleteRoute(router: LogstashPluginRouter) { { path: '/api/logstash/pipelines/delete', options: { - description: `Delete managed Logstash pipelines`, + summary: `Delete managed Logstash pipelines`, }, validate: { body: schema.object({ diff --git a/x-pack/plugins/logstash/server/routes/pipelines/list.ts b/x-pack/plugins/logstash/server/routes/pipelines/list.ts index e342acb72233b..30b4e1d08802c 100644 --- a/x-pack/plugins/logstash/server/routes/pipelines/list.ts +++ b/x-pack/plugins/logstash/server/routes/pipelines/list.ts @@ -28,7 +28,7 @@ export function registerPipelinesListRoute(router: LogstashPluginRouter) { { path: '/api/logstash/pipelines', options: { - description: `Get all managed Logstash pipelines`, + summary: `Get all managed Logstash pipelines`, }, validate: false, }, diff --git a/x-pack/plugins/ml/server/routes/saved_objects.ts b/x-pack/plugins/ml/server/routes/saved_objects.ts index a184a85eacd32..6d13b815ee338 100644 --- a/x-pack/plugins/ml/server/routes/saved_objects.ts +++ b/x-pack/plugins/ml/server/routes/saved_objects.ts @@ -78,7 +78,7 @@ export function savedObjectsRoutes( .get({ path: `${ML_EXTERNAL_BASE_PATH}/saved_objects/sync`, access: 'public', - description: 'Synchronize machine learning saved objects', + summary: 'Synchronize machine learning saved objects', options: { tags: [ 'access:ml:canCreateJob', diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts index 9414646ef9e43..8a481c4b60cbf 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts @@ -16,7 +16,7 @@ export function defineDeleteRolesRoutes({ router }: RouteDefinitionParams) { { path: '/api/security/role/{name}', options: { - description: `Delete a role`, + summary: `Delete a role`, }, validate: { params: schema.object({ name: schema.string({ minLength: 1 }) }), diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.ts index e14ebd09c98ed..9109d89d956fd 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.ts @@ -22,7 +22,7 @@ export function defineGetRolesRoutes({ { path: '/api/security/role/{name}', options: { - description: `Get a role`, + summary: `Get a role`, }, validate: { params: schema.object({ name: schema.string({ minLength: 1 }) }), diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts index 5732f493bf25d..a7d995f0a2639 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts @@ -22,7 +22,7 @@ export function defineGetAllRolesRoutes({ { path: '/api/security/role', options: { - description: `Get all roles`, + summary: `Get all roles`, }, validate: false, }, diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.ts index 337b0dc198b28..3a62b93819bd6 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.ts @@ -46,7 +46,7 @@ export function definePutRolesRoutes({ { path: '/api/security/role/{name}', options: { - description: `Create or update a role`, + summary: `Create or update a role`, }, validate: { params: schema.object({ name: schema.string({ minLength: 1, maxLength: 1024 }) }), diff --git a/x-pack/plugins/security/server/routes/session_management/invalidate.test.ts b/x-pack/plugins/security/server/routes/session_management/invalidate.test.ts index f1dad1c012f8c..ccd42b45718f8 100644 --- a/x-pack/plugins/security/server/routes/session_management/invalidate.test.ts +++ b/x-pack/plugins/security/server/routes/session_management/invalidate.test.ts @@ -44,7 +44,7 @@ describe('Invalidate sessions routes', () => { it('correctly defines route.', () => { expect(routeConfig.options).toEqual({ - description: 'Invalidate user sessions', + summary: 'Invalidate user sessions', tags: ['access:sessionManagement'], }); diff --git a/x-pack/plugins/security/server/routes/session_management/invalidate.ts b/x-pack/plugins/security/server/routes/session_management/invalidate.ts index 76a70a771b55c..1cf65bb9191c6 100644 --- a/x-pack/plugins/security/server/routes/session_management/invalidate.ts +++ b/x-pack/plugins/security/server/routes/session_management/invalidate.ts @@ -35,7 +35,7 @@ export function defineInvalidateSessionsRoutes({ router, getSession }: RouteDefi }, options: { tags: ['access:sessionManagement'], - description: `Invalidate user sessions`, + summary: `Invalidate user sessions`, }, }, async (_context, request, response) => { diff --git a/x-pack/plugins/task_manager/server/routes/health.ts b/x-pack/plugins/task_manager/server/routes/health.ts index 23539da937f93..38fd2e3b675ca 100644 --- a/x-pack/plugins/task_manager/server/routes/health.ts +++ b/x-pack/plugins/task_manager/server/routes/health.ts @@ -131,7 +131,7 @@ export function healthRoute(params: HealthRouteParams): { validate: false, options: { access: 'public', - description: `Get task manager health`, + summary: `Get task manager health`, }, }, async function ( diff --git a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/batch_reindex_indices.ts b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/batch_reindex_indices.ts index 391306aa18723..d2eb315aa4a66 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/batch_reindex_indices.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/batch_reindex_indices.ts @@ -38,7 +38,7 @@ export function registerBatchReindexIndicesRoutes( path: `${BASE_PATH}/batch/queue`, options: { access: 'public', - description: `Get the batch reindex queue`, + summary: `Get the batch reindex queue`, }, validate: {}, }, @@ -77,7 +77,7 @@ export function registerBatchReindexIndicesRoutes( path: `${BASE_PATH}/batch`, options: { access: 'public', - description: `Batch start or resume reindex`, + summary: `Batch start or resume reindex`, }, validate: { body: schema.object({ diff --git a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/reindex_indices.ts b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/reindex_indices.ts index 9b2b046169b77..11d34d48820e2 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/reindex_indices.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/reindex_indices.ts @@ -36,7 +36,7 @@ export function registerReindexIndicesRoutes( path: `${BASE_PATH}/{indexName}`, options: { access: 'public', - description: `Start or resume reindex`, + summary: `Start or resume reindex`, }, validate: { params: schema.object({ @@ -83,7 +83,7 @@ export function registerReindexIndicesRoutes( path: `${BASE_PATH}/{indexName}`, options: { access: 'public', - description: `Get reindex status`, + summary: `Get reindex status`, }, validate: { params: schema.object({ @@ -144,7 +144,7 @@ export function registerReindexIndicesRoutes( path: `${BASE_PATH}/{indexName}/cancel`, options: { access: 'public', - description: `Cancel reindex`, + summary: `Cancel reindex`, }, validate: { params: schema.object({ diff --git a/x-pack/plugins/upgrade_assistant/server/routes/status.ts b/x-pack/plugins/upgrade_assistant/server/routes/status.ts index 7a44981776319..de621da5a23b1 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/status.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/status.ts @@ -26,7 +26,7 @@ export function registerUpgradeStatusRoute({ path: `${API_BASE_PATH}/status`, options: { access: 'public', - description: `Get upgrade readiness status`, + summary: `Get upgrade readiness status`, }, validate: false, }, From 53b445833fa59cafd33ec86c40f61e5ae3770c18 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Thu, 6 Jun 2024 16:55:19 +0300 Subject: [PATCH 15/87] Add support for a declarative (via configuration) way to specify Kibana feature overrides (#180362) ## Summary This PR extends the features plugin to accept feature definition overrides via Kibana configuration. The functionality is limited to the Serverless offering only. Additionally, the PR updates Kibana serverless configurations to include overrides based on the "simplified feature toggles" proposals discussed with the solution teams. The configuration might look like this: ```yaml ## Fine-tune the feature privileges. xpack.features.overrides: dashboard: privileges: ### Dashboard's `All` feature privilege should implicitly ### grant `All` access to Maps and Visualize features. all.composedOf: - feature: "maps" privileges: [ "all" ] - feature: "visualize" privileges: [ "all" ] ### All Dashboard sub-feature privileges should be hidden: ### reporting capabilities will be granted via dedicated ### Reporting feature and short URL sub-feature privilege ### should be granted for both `All` and `Read`. subFeatures.privileges: download_csv_report.disabled: true url_create: disabled: true includeIn: "read" ### Maps feature is disabled since it's automatically granted by Dashboard feature. maps.disabled: true ``` ## How to test Log in as the `admin` using SAML and navigate to the `Custom roles` management section to edit role and see tuned role management UX:

![image](https://github.com/elastic/kibana/assets/1713708/5e27a49b-4382-4a91-bb85-eca929a27961) ### Search project ```bash yarn es serverless --projectType=es --ssl -E xpack.security.authc.native_roles.enabled=true yarn start --serverless=es --ssl --xpack.security.roleManagementEnabled=true ``` Refer to the proposal document, `config/serverless.yml`, and `config/serverless.es.yml` in this PR to see the specific changes made for your project type: ![image](https://github.com/elastic/kibana/assets/1713708/9f9d0341-32a1-4258-be3b-d3a809f5bacc) Create a custom `custom-search` role and re-login as the user with this role to test your project type (you need to manually type role name if the role selector):

### Observability project ```bash yarn es serverless --projectType=oblt --ssl -E xpack.security.authc.native_roles.enabled=true yarn start --serverless=oblt --ssl --xpack.security.roleManagementEnabled=true ``` Refer to the proposal document, `config/serverless.yml`, and `config/serverless.oblt.yml` in this PR to see the specific changes made for your project type: ![image](https://github.com/elastic/kibana/assets/1713708/1d2b360a-24ab-47f7-ac9b-8ad944949c32) Create a custom `custom-o11y` role and re-login as the user with this role to test your project type (you need to manually type role name if the role selector):

### Security project ```bash yarn es serverless --projectType=security --ssl -E xpack.security.authc.native_roles.enabled=true yarn start --serverless=security --ssl --xpack.security.roleManagementEnabled=true ``` Refer to the proposal document, `config/serverless.yml`, and `config/serverless.security.yml` in this PR to see the specific changes made for your project type: ![image](https://github.com/elastic/kibana/assets/1713708/2dbca002-59f1-44f0-9ab2-1dd205e48da8) Create a custom `custom-security` role and re-login as the user with this role to test your project type (you need to manually type role name if the role selector):

__Fixes: https://github.com/elastic/kibana/issues/178963__ --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 7 + config/serverless.es.yml | 16 + config/serverless.oblt.yml | 98 + config/serverless.security.yml | 37 + config/serverless.yml | 53 + .../common/feature_kibana_privileges.ts | 9 + .../feature_kibana_privileges_reference.ts | 20 + x-pack/plugins/features/common/index.ts | 1 + .../plugins/features/common/kibana_feature.ts | 11 + x-pack/plugins/features/common/sub_feature.ts | 2 +- x-pack/plugins/features/server/config.test.ts | 160 + x-pack/plugins/features/server/config.ts | 74 + .../features/server/feature_registry.test.ts | 265 + .../features/server/feature_registry.ts | 115 + .../plugins/features/server/feature_schema.ts | 2 + x-pack/plugins/features/server/index.ts | 5 +- x-pack/plugins/features/server/plugin.test.ts | 73 + x-pack/plugins/features/server/plugin.ts | 7 + x-pack/plugins/reporting/server/core.ts | 37 +- x-pack/plugins/reporting/server/features.ts | 74 + .../plugins/reporting/server/plugin.test.ts | 45 +- x-pack/plugins/reporting/server/plugin.ts | 10 +- .../roles/edit_role/edit_role_page.tsx | 2 +- .../kibana/feature_table/sub_feature_form.tsx | 4 +- .../roles/model/secured_sub_feature.ts | 40 +- .../roles/model/sub_feature_privilege.ts | 4 + .../privileges/privileges.test.ts | 942 +- .../authorization/privileges/privileges.ts | 91 +- .../security/server/lib/role_utils.test.ts | 168 +- .../plugins/security/server/lib/role_utils.ts | 29 +- .../common/platform_security/authorization.ts | 48 + .../observability/index.feature_flags.ts | 1 + .../platform_security/authorization.ts | 9585 +++++++++++++++++ .../observability/platform_security/index.ts | 14 + .../test_suites/search/index.feature_flags.ts | 1 + .../search/platform_security/authorization.ts | 1029 ++ .../search/platform_security/index.ts | 14 + .../security/index.feature_flags.ts | 1 + .../platform_security/authorization.ts | 2412 +++++ .../security/platform_security/index.ts | 14 + x-pack/test_serverless/tsconfig.json | 3 +- 41 files changed, 15408 insertions(+), 115 deletions(-) create mode 100644 x-pack/plugins/features/common/feature_kibana_privileges_reference.ts create mode 100644 x-pack/plugins/features/server/config.test.ts create mode 100644 x-pack/plugins/features/server/config.ts create mode 100644 x-pack/plugins/reporting/server/features.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/platform_security/authorization.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/platform_security/index.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/search/platform_security/authorization.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/search/platform_security/index.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/security/platform_security/authorization.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/security/platform_security/index.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d9a9f60eef539..322780e137b67 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1249,6 +1249,10 @@ x-pack/test/observability_ai_assistant_functional @elastic/obs-ai-assistant # Core /config/ @elastic/kibana-core +/config/serverless.yml @elastic/kibana-core @elastic/kibana-security +/config/serverless.es.yml @elastic/kibana-core @elastic/kibana-security +/config/serverless.oblt.yml @elastic/kibana-core @elastic/kibana-security +/config/serverless.security.yml @elastic/kibana-core @elastic/kibana-security /typings/ @elastic/kibana-core /test/analytics @elastic/kibana-core /packages/kbn-test/src/jest/setup/mocks.kbn_i18n_react.js @elastic/kibana-core @@ -1307,6 +1311,9 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/test/spaces_api_integration/ @elastic/kibana-security /x-pack/test/saved_object_api_integration/ @elastic/kibana-security /x-pack/test_serverless/**/test_suites/common/platform_security/ @elastic/kibana-security +/x-pack/test_serverless/**/test_suites/search/platform_security/ @elastic/kibana-security +/x-pack/test_serverless/**/test_suites/security/platform_security/ @elastic/kibana-security +/x-pack/test_serverless/**/test_suites/observability/platform_security/ @elastic/kibana-security /packages/core/http/core-http-server-internal/src/cdn_config/ @elastic/kibana-security @elastic/kibana-core #CC# /x-pack/plugins/security/ @elastic/kibana-security diff --git a/config/serverless.es.yml b/config/serverless.es.yml index ed71ce0d7819c..0a609b0d40b2c 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -12,6 +12,22 @@ xpack.serverless.observability.enabled: false enterpriseSearch.enabled: false xpack.fleet.enabled: false xpack.observabilityAIAssistant.enabled: false +xpack.osquery.enabled: false + +## Fine-tune the search solution feature privileges. Also, refer to `serverless.yml` for the project-agnostic overrides. +xpack.features.overrides: + ### Dashboards feature is moved from Analytics category to the Search one. + dashboard.category: "enterpriseSearch" + ### Dev Tools feature is moved from Analytics category to the Search one. + dev_tools.category: "enterpriseSearch" + ### Discover feature is moved from Analytics category to the Search one. + discover.category: "enterpriseSearch" + ### Machine Learning feature is moved from Analytics category to the Management one. + ml.category: "management" + ### Stack Alerts feature is moved from Analytics category to the Search one renamed to simply `Alerts`. + stackAlerts: + name: "Alerts" + category: "enterpriseSearch" ## Cloud settings xpack.cloud.serverless.project_type: search diff --git a/config/serverless.oblt.yml b/config/serverless.oblt.yml index 0d1add8e63f95..3cee8b352756e 100644 --- a/config/serverless.oblt.yml +++ b/config/serverless.oblt.yml @@ -8,6 +8,104 @@ xpack.uptime.enabled: true xpack.securitySolution.enabled: false xpack.search.notebooks.enabled: false +## Fine-tune the observability solution feature privileges. Also, refer to `serverless.yml` for the project-agnostic overrides. +xpack.features.overrides: + ### Applications feature privileges are fine-tuned to grant access to Logs, and Observability apps. + apm: + ### By default, this feature named as `APM and User Experience`, but should be renamed to `Applications`. + name: "Applications" + privileges: + # Infrastructure's `All` feature privilege should implicitly grant `All` access to Logs and Observability apps. + all.composedOf: + - feature: "logs" + privileges: [ "all" ] + - feature: "observability" + privileges: [ "all" ] + # Infrastructure's `Read` feature privilege should implicitly grant `Read` access to Logs and Observability apps. + read.composedOf: + - feature: "logs" + privileges: [ "read" ] + - feature: "observability" + privileges: [ "read" ] + ### Dashboards feature should be moved from Analytics category to the Observability one. + dashboard.category: "observability" + ### Discover feature should be moved from Analytics category to the Observability one and its privileges are + ### fine-tuned to grant access to Observability app. + discover: + category: "observability" + privileges: + # Discover `All` feature privilege should implicitly grant `All` access to Observability app. + all.composedOf: + - feature: "observability" + privileges: [ "all" ] + # Discover `Read` feature privilege should implicitly grant `Read` access to Observability app. + read.composedOf: + - feature: "observability" + privileges: [ "read" ] + ### Fleet feature privileges are fine-tuned to grant access to Logs app. + fleetv2: + privileges: + # Fleet `All` feature privilege should implicitly grant `All` access to Logs app. + all.composedOf: + - feature: "logs" + privileges: [ "all" ] + # Fleet `Read` feature privilege should implicitly grant `Read` access to Logs app. + read.composedOf: + - feature: "logs" + privileges: [ "read" ] + ### Infrastructure feature privileges are fine-tuned to grant access to Logs, and Observability apps. + infrastructure: + ### By default, this feature named as `Metrics`, but should be renamed to `Infrastructure`. + name: "Infrastructure" + privileges: + # Infrastructure's `All` feature privilege should implicitly grant `All` access to Logs and Observability apps. + all.composedOf: + - feature: "logs" + privileges: [ "all" ] + - feature: "observability" + privileges: [ "all" ] + # Infrastructure's `Read` feature privilege should implicitly grant `Read` access to Logs and Observability apps. + read.composedOf: + - feature: "logs" + privileges: [ "read" ] + - feature: "observability" + privileges: [ "read" ] + ### Logs feature is hidden in Role management since it's automatically granted by either Infrastructure, or Applications features. + logs.hidden: true + ### Machine Learning feature should be moved from Analytics category to the Observability one and renamed to `AI Ops`. + ml: + category: "observability" + order: 1200 + ### Observability feature is hidden in Role management since it's automatically granted by either Discover, + ### Infrastructure, Applications, Synthetics, or SLOs features. + observability.hidden: true + ### SLOs feature privileges are fine-tuned to grant access to Observability app. + slo: + privileges: + # SLOs `All` feature privilege should implicitly grant `All` access to Observability app. + all.composedOf: + - feature: "observability" + privileges: [ "all" ] + # SLOs `Read` feature privilege should implicitly grant `Read` access to Observability app. + read.composedOf: + - feature: "observability" + privileges: [ "read" ] + ### Stack alerts is hidden in Role management since it's not needed. + stackAlerts.hidden: true + ### Synthetics feature privileges are fine-tuned to grant access to Observability app. + uptime: + ### By default, this feature named as `Synthetics and Uptime`, but should be renamed to `Synthetics` since `Uptime` is not available. + name: "Synthetics" + privileges: + # Synthetics `All` feature privilege should implicitly grant `All` access to Observability app. + all.composedOf: + - feature: "observability" + privileges: [ "all" ] + # Synthetics `Read` feature privilege should implicitly grant `Read` access to Observability app. + read.composedOf: + - feature: "observability" + privileges: [ "read" ] + ## Enable the slo plugin xpack.slo.enabled: true diff --git a/config/serverless.security.yml b/config/serverless.security.yml index 88770178a3493..6f39182d1e2e6 100644 --- a/config/serverless.security.yml +++ b/config/serverless.security.yml @@ -9,6 +9,43 @@ xpack.observability.enabled: false xpack.observabilityAIAssistant.enabled: false xpack.search.notebooks.enabled: false +## Fine-tune the security solution feature privileges. Also, refer to `serverless.yml` for the project-agnostic overrides. +xpack.features.overrides: + ### Dashboard feature is hidden in Role management since it's automatically granted by SIEM feature. + dashboard.hidden: true + ### Discover feature is hidden in Role management since it's automatically granted by SIEM feature. + discover.hidden: true + ### Machine Learning feature is moved from Analytics category to the Security one as the last item. + ml: + category: "security" + order: 1101 + ### Security's feature privileges are fine-tuned to grant access to Discover, Dashboard, Maps, and Visualize apps. + siem: + privileges: + ### Security's `All` feature privilege should implicitly grant `All` access to Discover, Dashboard, Maps, and + ### Visualize features. + all.composedOf: + - feature: "discover" + privileges: [ "all" ] + - feature: "dashboard" + privileges: [ "all" ] + - feature: "visualize" + privileges: [ "all" ] + - feature: "maps" + privileges: [ "all" ] + # Security's `Read` feature privilege should implicitly grant `Read` access to Discover, Dashboard, Maps, and + # Visualize features. Additionally, it should implicitly grant privilege to create short URLs in Discover, + ### Dashboard, and Visualize apps. + read.composedOf: + - feature: "discover" + privileges: [ "read" ] + - feature: "dashboard" + privileges: [ "read" ] + - feature: "visualize" + privileges: [ "read" ] + - feature: "maps" + privileges: [ "read" ] + ## Cloud settings xpack.cloud.serverless.project_type: security diff --git a/config/serverless.yml b/config/serverless.yml index 43ac498e0901d..6631441e3b5dd 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -8,6 +8,59 @@ xpack.fleet.internal.activeAgentsSoftLimit: 25000 xpack.fleet.internal.onlyAllowAgentUpgradeToKnownVersions: true xpack.fleet.internal.retrySetupOnBoot: true +## Fine-tune the feature privileges. +xpack.features.overrides: + dashboard: + privileges: + ### Dashboard's `All` feature privilege should implicitly grant `All` access to Maps and Visualize features. + all.composedOf: + - feature: "maps" + privileges: [ "all" ] + - feature: "visualize" + privileges: [ "all" ] + ### Dashboard's `Read` feature privilege should implicitly grant `Read` access to Maps and Visualize features. + ### Additionally, it should implicitly grant privilege to create short URLs in Visualize app. + read.composedOf: + - feature: "maps" + privileges: [ "read" ] + - feature: "visualize" + privileges: [ "read" ] + ### All Dashboard sub-feature privileges should be hidden: reporting capabilities will be granted via dedicated + ### Reporting feature and short URL sub-feature privilege should be granted for both `All` and `Read`. + subFeatures.privileges: + download_csv_report.disabled: true + generate_report.disabled: true + store_search_session.disabled: true + url_create: + disabled: true + includeIn: "read" + discover: + ### All Discover sub-feature privileges should be hidden: reporting capabilities will be granted via dedicated + ### Reporting feature and short URL sub-feature privilege should be granted for both `All` and `Read`. + subFeatures.privileges: + generate_report.disabled: true + store_search_session.disabled: true + url_create: + disabled: true + includeIn: "read" + ### Shared images feature is hidden in Role management since it's not needed. + filesSharedImage.hidden: true + ### Maps feature is hidden in Role management since it's automatically granted by Dashboard feature. + maps.hidden: true + ### Reporting feature is supposed to give access to reporting capabilities across different features. + reporting: + privileges: + all.composedOf: + - feature: "dashboard" + privileges: [ "download_csv_report" ] + - feature: "discover" + privileges: [ "generate_report" ] + ### Visualize feature is hidden in Role management since it's automatically granted by Dashboard feature. + visualize: + hidden: true + ### The short URL sub-feature privilege should be always granted. + subFeatures.privileges.url_create.includeIn: "read" + # Cloud links xpack.cloud.base_url: 'https://cloud.elastic.co' diff --git a/x-pack/plugins/features/common/feature_kibana_privileges.ts b/x-pack/plugins/features/common/feature_kibana_privileges.ts index 49c001c890b69..54913e08223c5 100644 --- a/x-pack/plugins/features/common/feature_kibana_privileges.ts +++ b/x-pack/plugins/features/common/feature_kibana_privileges.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { FeatureKibanaPrivilegesReference } from './feature_kibana_privileges_reference'; + /** * Feature privilege definition */ @@ -263,4 +265,11 @@ export interface FeatureKibanaPrivileges { * @see UICapabilities */ ui: readonly string[]; + + /** + * An optional list of other registered feature or sub-feature privileges that this privilege is composed of. When + * privilege is registered with Elasticsearch, it will be expanded to grant everything that referenced privileges + * grant. This property can only be set in the feature configuration overrides. + */ + composedOf?: readonly FeatureKibanaPrivilegesReference[]; } diff --git a/x-pack/plugins/features/common/feature_kibana_privileges_reference.ts b/x-pack/plugins/features/common/feature_kibana_privileges_reference.ts new file mode 100644 index 0000000000000..3835579fbdb59 --- /dev/null +++ b/x-pack/plugins/features/common/feature_kibana_privileges_reference.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Defines a reference to a set of privileges of a specific feature. + */ +export interface FeatureKibanaPrivilegesReference { + /** + * The ID of the feature. + */ + feature: string; + /** + * The set of IDs of feature or sub-feature privileges provided by the feature. + */ + privileges: readonly string[]; +} diff --git a/x-pack/plugins/features/common/index.ts b/x-pack/plugins/features/common/index.ts index 9db2a1073cd07..92cbcd76172d0 100644 --- a/x-pack/plugins/features/common/index.ts +++ b/x-pack/plugins/features/common/index.ts @@ -18,3 +18,4 @@ export type { SubFeaturePrivilegeGroupType, } from './sub_feature'; export { SubFeature } from './sub_feature'; +export type { FeatureKibanaPrivilegesReference } from './feature_kibana_privileges_reference'; diff --git a/x-pack/plugins/features/common/kibana_feature.ts b/x-pack/plugins/features/common/kibana_feature.ts index debcec588dee0..926aca01627a2 100644 --- a/x-pack/plugins/features/common/kibana_feature.ts +++ b/x-pack/plugins/features/common/kibana_feature.ts @@ -142,6 +142,13 @@ export interface KibanaFeatureConfig { description: string; privileges: readonly ReservedKibanaPrivilege[]; }; + + /** + * Indicates whether the feature is available as a standalone feature. The feature can still be + * referenced by other features, but it will not be displayed in any feature management UIs. By default, all features + * are visible. + */ + hidden?: boolean; } export class KibanaFeature { @@ -157,6 +164,10 @@ export class KibanaFeature { return this.config.id; } + public get hidden() { + return this.config.hidden; + } + public get name() { return this.config.name; } diff --git a/x-pack/plugins/features/common/sub_feature.ts b/x-pack/plugins/features/common/sub_feature.ts index e51fc42195797..a87dc2343e16d 100644 --- a/x-pack/plugins/features/common/sub_feature.ts +++ b/x-pack/plugins/features/common/sub_feature.ts @@ -70,7 +70,7 @@ export interface SubFeaturePrivilegeGroupConfig { * Configuration for a sub-feature privilege. */ export interface SubFeaturePrivilegeConfig - extends Omit { + extends Omit { /** * Identifier for this privilege. Must be unique across all other privileges within a feature. */ diff --git a/x-pack/plugins/features/server/config.test.ts b/x-pack/plugins/features/server/config.test.ts new file mode 100644 index 0000000000000..096a7f8b9477e --- /dev/null +++ b/x-pack/plugins/features/server/config.test.ts @@ -0,0 +1,160 @@ +/* + * 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 { ConfigSchema } from './config'; +import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; + +describe('config schema', () => { + it('generates proper defaults (no overrides)', () => { + expect(ConfigSchema.validate({})).toMatchInlineSnapshot(`Object {}`); + expect(ConfigSchema.validate({}, { serverless: true })).toMatchInlineSnapshot(`Object {}`); + }); + + it('does not allow overrides in non-serverless', () => { + expect(() => + ConfigSchema.validate( + { overrides: { featureA: { name: 'new name' } } }, + { serverless: false } + ) + ).toThrowErrorMatchingInlineSnapshot(`"[overrides]: a value wasn't expected to be present"`); + expect( + ConfigSchema.validate({ overrides: { featureA: { name: 'new name' } } }, { serverless: true }) + ).toMatchInlineSnapshot(` + Object { + "overrides": Object { + "featureA": Object { + "name": "new name", + }, + }, + } + `); + }); + + it('can override feature properties', () => { + expect( + ConfigSchema.validate( + { + overrides: { + featureA: { name: 'new name', hidden: true }, + featureB: { + order: 100, + category: 'management', + privileges: { + all: { + disabled: true, + }, + read: { + composedOf: [{ feature: 'featureC', privileges: ['all', 'read'] }], + }, + }, + }, + featureC: { + subFeatures: { + privileges: { + subOne: { + disabled: true, + includeIn: 'all', + }, + subTwo: { + includeIn: 'none', + }, + }, + }, + }, + }, + }, + { serverless: true } + ) + ).toMatchInlineSnapshot(` + Object { + "overrides": Object { + "featureA": Object { + "hidden": true, + "name": "new name", + }, + "featureB": Object { + "category": "management", + "order": 100, + "privileges": Object { + "all": Object { + "disabled": true, + }, + "read": Object { + "composedOf": Array [ + Object { + "feature": "featureC", + "privileges": Array [ + "all", + "read", + ], + }, + ], + }, + }, + }, + "featureC": Object { + "subFeatures": Object { + "privileges": Object { + "subOne": Object { + "disabled": true, + "includeIn": "all", + }, + "subTwo": Object { + "includeIn": "none", + }, + }, + }, + }, + }, + } + `); + }); + + it('properly validates category override', () => { + for (const category of Object.keys(DEFAULT_APP_CATEGORIES)) { + expect( + ConfigSchema.validate({ overrides: { featureA: { category } } }, { serverless: true }) + .overrides?.featureA.category + ).toBe(category); + } + + expect(() => + ConfigSchema.validate( + { overrides: { featureA: { category: 'unknown' } } }, + { serverless: true } + ) + ).toThrowErrorMatchingInlineSnapshot( + `"[overrides.featureA.category]: Unknown category \\"unknown\\". Should be one of kibana, enterpriseSearch, observability, security, management"` + ); + }); + it('properly validates sub-feature privilege inclusion override', () => { + for (const includeIn of ['all', 'read', 'none']) { + expect( + ConfigSchema.validate( + { overrides: { featureA: { subFeatures: { privileges: { subOne: { includeIn } } } } } }, + { serverless: true } + ).overrides?.featureA.subFeatures?.privileges.subOne.includeIn + ).toBe(includeIn); + } + + expect(() => + ConfigSchema.validate( + { + overrides: { + featureA: { subFeatures: { privileges: { subOne: { includeIn: 'write' } } } }, + }, + }, + { serverless: true } + ) + ).toThrowErrorMatchingInlineSnapshot(` + "[overrides.featureA.subFeatures.privileges.subOne.includeIn]: types that failed validation: + - [includeIn.0]: expected value to equal [all] + - [includeIn.1]: expected value to equal [read] + - [includeIn.2]: expected value to equal [none]" + `); + }); +}); diff --git a/x-pack/plugins/features/server/config.ts b/x-pack/plugins/features/server/config.ts new file mode 100644 index 0000000000000..c4941b0eef90e --- /dev/null +++ b/x-pack/plugins/features/server/config.ts @@ -0,0 +1,74 @@ +/* + * 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 { offeringBasedSchema, schema, type TypeOf } from '@kbn/config-schema'; +import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; + +const privilegeOverrideSchema = schema.maybe( + schema.object({ + disabled: schema.maybe(schema.boolean()), + composedOf: schema.maybe( + schema.arrayOf( + schema.object({ + feature: schema.string(), + privileges: schema.arrayOf(schema.string()), + }) + ) + ), + }) +); + +export type ConfigType = TypeOf; +export type ConfigOverridesType = Required['overrides']; +export const ConfigSchema = schema.object({ + overrides: offeringBasedSchema({ + // Overrides are only exposed in Serverless offering. + serverless: schema.maybe( + // Key is the feature ID, value is a set of feature properties to override. + schema.recordOf( + schema.string(), + schema.object({ + hidden: schema.maybe(schema.boolean()), + name: schema.maybe(schema.string({ minLength: 1 })), + category: schema.maybe( + schema.string({ + validate(categoryName) { + if (!Object.hasOwn(DEFAULT_APP_CATEGORIES, categoryName)) { + return `Unknown category "${categoryName}". Should be one of ${Object.keys( + DEFAULT_APP_CATEGORIES + ).join(', ')}`; + } + }, + }) + ), + order: schema.maybe(schema.number()), + privileges: schema.maybe( + schema.object({ all: privilegeOverrideSchema, read: privilegeOverrideSchema }) + ), + subFeatures: schema.maybe( + schema.object({ + // Key is the ID of the sub-feature privilege, value is a set of privilege properties to override. + privileges: schema.recordOf( + schema.string(), + schema.object({ + disabled: schema.maybe(schema.boolean()), + includeIn: schema.maybe( + schema.oneOf([ + schema.literal('all'), + schema.literal('read'), + schema.literal('none'), + ]) + ), + }) + ), + }) + ), + }) + ) + ), + }), +}); diff --git a/x-pack/plugins/features/server/feature_registry.test.ts b/x-pack/plugins/features/server/feature_registry.test.ts index e0d0591c67d88..f27c93ac9129e 100644 --- a/x-pack/plugins/features/server/feature_registry.test.ts +++ b/x-pack/plugins/features/server/feature_registry.test.ts @@ -8,6 +8,7 @@ import { FeatureRegistry } from './feature_registry'; import { ElasticsearchFeatureConfig, KibanaFeatureConfig } from '../common'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; +import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; describe('FeatureRegistry', () => { describe('Kibana Features', () => { @@ -1930,6 +1931,270 @@ describe('FeatureRegistry', () => { expect(withSubFeature.subFeatures[0].privilegeGroups[0].privileges).toHaveLength(0); }); }); + + describe('#applyOverrides', () => { + let registry: FeatureRegistry; + beforeEach(() => { + registry = new FeatureRegistry(); + const features: KibanaFeatureConfig[] = [ + { + id: 'featureA', + name: 'Feature A', + app: [], + order: 1, + category: { id: 'fooA', label: 'fooA' }, + privileges: { + all: { ui: [], savedObject: { all: [], read: [] } }, + read: { ui: [], savedObject: { all: [], read: [] } }, + }, + }, + { + id: 'featureB', + name: 'Feature B', + app: [], + order: 2, + category: { id: 'fooB', label: 'fooB' }, + privileges: null, + }, + { + id: 'featureC', + name: 'Feature C', + app: [], + order: 1, + category: { id: 'fooC', label: 'fooC' }, + privileges: { + all: { ui: [], savedObject: { all: [], read: [] } }, + read: { ui: [], savedObject: { all: [], read: [] } }, + }, + subFeatures: [ + { + name: 'subFeatureC', + privilegeGroups: [ + { + groupType: 'mutually_exclusive', + privileges: [ + { + id: 'subFeatureCOne', + name: 'subFeature C One', + includeIn: 'all', + ui: [], + savedObject: { all: [], read: [] }, + }, + ], + }, + ], + }, + ], + }, + { + id: 'featureD', + name: 'Feature D', + app: [], + order: 1, + category: { id: 'fooD', label: 'fooD' }, + privileges: { + all: { ui: [], savedObject: { all: [], read: [] } }, + read: { ui: [], savedObject: { all: [], read: [] } }, + }, + }, + { + id: 'featureE', + name: 'Feature E', + app: [], + order: 1, + category: { id: 'fooE', label: 'fooE' }, + privileges: { + all: { + ui: [], + savedObject: { all: [], read: [] }, + alerting: { alert: { all: ['one'] } }, + }, + read: { ui: [], savedObject: { all: [], read: [] } }, + }, + alerting: ['one'], + }, + ]; + features.forEach((f) => registry.registerKibanaFeature(f)); + }); + + it('rejects overrides for unknown features', () => { + expect(() => + registry.applyOverrides({ unknownFeature: {} }) + ).toThrowErrorMatchingInlineSnapshot( + `"Cannot override feature \\"unknownFeature\\" since feature with such ID is not registered."` + ); + }); + + it('can override basic feature properties', () => { + registry.applyOverrides({ + featureA: { + hidden: true, + name: 'Feature A New', + category: 'management', + order: 123, + }, + }); + registry.lockRegistration(); + + const [featureA, featureB] = registry.getAllKibanaFeatures(); + expect(featureA.hidden).toBe(true); + expect(featureB.hidden).toBeUndefined(); + + expect(featureA.name).toBe('Feature A New'); + expect(featureB.name).toBe('Feature B'); + + expect(featureA.category).toEqual(DEFAULT_APP_CATEGORIES.management); + expect(featureB.category).toEqual({ id: 'fooB', label: 'fooB' }); + + expect(featureA.order).toBe(123); + expect(featureB.order).toBe(2); + }); + + it('rejects overrides for unknown privileges', () => { + expect(() => + registry.applyOverrides({ featureB: { privileges: { all: { disabled: true } } } }) + ).toThrowErrorMatchingInlineSnapshot( + `"Cannot override privilege \\"all\\" of feature \\"featureB\\" since \\"all\\" privilege is not registered."` + ); + }); + + it('rejects overrides for `composedOf` referring to unknown feature', () => { + expect(() => + registry.applyOverrides({ + featureA: { + privileges: { + all: { composedOf: [{ feature: 'featureF', privileges: ['all'] }] }, + }, + }, + }) + ).toThrowErrorMatchingInlineSnapshot( + `"Cannot compose privilege \\"all\\" of feature \\"featureA\\" with privileges of feature \\"featureF\\" since such feature is not registered."` + ); + }); + + it('rejects overrides for `composedOf` referring to unknown feature privilege', () => { + expect(() => + registry.applyOverrides({ + featureA: { + privileges: { + all: { composedOf: [{ feature: 'featureB', privileges: ['none'] }] }, + }, + }, + }) + ).toThrowErrorMatchingInlineSnapshot( + `"Cannot compose privilege \\"all\\" of feature \\"featureA\\" with privilege \\"none\\" of feature \\"featureB\\" since such privilege is not registered."` + ); + }); + + it('can override `composedOf` referring to both feature and sub-feature privileges', () => { + registry.applyOverrides({ + featureA: { + privileges: { + all: { + composedOf: [ + { feature: 'featureC', privileges: ['subFeatureCOne'] }, + { feature: 'featureD', privileges: ['all'] }, + ], + }, + read: { composedOf: [{ feature: 'featureD', privileges: ['read'] }] }, + }, + }, + }); + registry.lockRegistration(); + + const [featureA] = registry.getAllKibanaFeatures(); + expect(featureA.privileges).toEqual({ + all: { + ui: [], + savedObject: { all: ['telemetry'], read: ['config', 'config-global', 'url'] }, + composedOf: [ + { feature: 'featureC', privileges: ['subFeatureCOne'] }, + { feature: 'featureD', privileges: ['all'] }, + ], + }, + read: { + ui: [], + savedObject: { all: [], read: ['config', 'config-global', 'telemetry', 'url'] }, + composedOf: [{ feature: 'featureD', privileges: ['read'] }], + }, + }); + }); + + it('can override `composedOf` referring to a feature that requires custom RBAC', () => { + registry.applyOverrides({ + featureA: { + privileges: { + all: { composedOf: [{ feature: 'featureE', privileges: ['all'] }] }, + }, + }, + }); + registry.lockRegistration(); + + const [featureA] = registry.getAllKibanaFeatures(); + expect(featureA.privileges).toEqual({ + all: { + ui: [], + savedObject: { all: ['telemetry'], read: ['config', 'config-global', 'url'] }, + composedOf: [{ feature: 'featureE', privileges: ['all'] }], + }, + read: { + ui: [], + savedObject: { all: [], read: ['config', 'config-global', 'telemetry', 'url'] }, + }, + }); + }); + + it('rejects overrides for unknown sub-feature privileges', () => { + expect(() => + registry.applyOverrides({ + featureC: { subFeatures: { privileges: { all: { disabled: true } } } }, + }) + ).toThrowErrorMatchingInlineSnapshot( + `"Cannot override sub-feature privilege \\"all\\" of feature \\"featureC\\" since \\"all\\" sub-feature privilege is not registered. Known sub-feature privileges are: subFeatureCOne."` + ); + + expect(() => + registry.applyOverrides({ + featureA: { subFeatures: { privileges: { subFeatureCOne: { disabled: true } } } }, + }) + ).toThrowErrorMatchingInlineSnapshot( + `"Cannot override sub-feature privileges of feature \\"featureA\\" since it didn't register any."` + ); + }); + + it('can override sub-feature privileges', () => { + registry.applyOverrides({ + featureC: { + subFeatures: { privileges: { subFeatureCOne: { disabled: true, includeIn: 'none' } } }, + }, + }); + registry.lockRegistration(); + + const [, , featureC] = registry.getAllKibanaFeatures(); + expect(featureC.subFeatures).toEqual([ + { + config: { + name: 'subFeatureC', + privilegeGroups: [ + { + groupType: 'mutually_exclusive', + privileges: [ + { + disabled: true, + id: 'subFeatureCOne', + includeIn: 'none', + name: 'subFeature C One', + savedObject: { all: [], read: [] }, + ui: [], + }, + ], + }, + ], + }, + }, + ]); + }); + }); }); describe('Elasticsearch Features', () => { diff --git a/x-pack/plugins/features/server/feature_registry.ts b/x-pack/plugins/features/server/feature_registry.ts index 40c278b2fe4ed..4726335ee3d01 100644 --- a/x-pack/plugins/features/server/feature_registry.ts +++ b/x-pack/plugins/features/server/feature_registry.ts @@ -7,14 +7,17 @@ import { cloneDeep, uniq } from 'lodash'; import { ILicense } from '@kbn/licensing-plugin/server'; +import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { KibanaFeatureConfig, KibanaFeature, FeatureKibanaPrivileges, ElasticsearchFeatureConfig, ElasticsearchFeature, + SubFeaturePrivilegeConfig, } from '../common'; import { validateKibanaFeature, validateElasticsearchFeature } from './feature_schema'; +import type { ConfigOverridesType } from './config'; export class FeatureRegistry { private locked = false; @@ -61,6 +64,106 @@ export class FeatureRegistry { this.esFeatures[feature.id] = featureCopy; } + /** + * Updates definitions for the registered features using configuration overrides, if any. + */ + public applyOverrides(overrides: ConfigOverridesType) { + for (const [featureId, featureOverride] of Object.entries(overrides)) { + const feature = this.kibanaFeatures[featureId]; + if (!feature) { + throw new Error( + `Cannot override feature "${featureId}" since feature with such ID is not registered.` + ); + } + + if (featureOverride.hidden) { + feature.hidden = featureOverride.hidden; + } + + // Note that the name doesn't currently support localizable strings. We'll revisit this approach when i18n support + // becomes necessary. + if (featureOverride.name) { + feature.name = featureOverride.name; + } + + if (featureOverride.category) { + feature.category = DEFAULT_APP_CATEGORIES[featureOverride.category]; + } + + if (featureOverride.order != null) { + feature.order = featureOverride.order; + } + + if (featureOverride.privileges) { + for (const [privilegeId, privilegeOverride] of Object.entries(featureOverride.privileges)) { + const typedPrivilegeId = privilegeId as 'read' | 'all'; + const targetPrivilege = feature.privileges?.[typedPrivilegeId]; + if (!targetPrivilege) { + throw new Error( + `Cannot override privilege "${privilegeId}" of feature "${featureId}" since "${privilegeId}" privilege is not registered.` + ); + } + + for (const featureReference of privilegeOverride.composedOf ?? []) { + const referencedFeature = this.kibanaFeatures[featureReference.feature]; + if (!referencedFeature) { + throw new Error( + `Cannot compose privilege "${privilegeId}" of feature "${featureId}" with privileges of feature "${featureReference.feature}" since such feature is not registered.` + ); + } + + // Collect all known feature and sub-feature privileges for the referenced feature. + const knownPrivileges = new Map( + Object.entries(referencedFeature.privileges ?? {}).concat( + collectSubFeaturesPrivileges(referencedFeature) + ) + ); + + for (const privilegeReference of featureReference.privileges) { + const referencedPrivilege = knownPrivileges.get(privilegeReference); + if (!referencedPrivilege) { + throw new Error( + `Cannot compose privilege "${privilegeId}" of feature "${featureId}" with privilege "${privilegeReference}" of feature "${featureReference.feature}" since such privilege is not registered.` + ); + } + } + } + + // It's safe to assume that `feature.privileges` is defined here since we've checked it above. + feature.privileges![typedPrivilegeId] = { ...targetPrivilege, ...privilegeOverride }; + } + } + + if (featureOverride.subFeatures?.privileges) { + // Collect all known sub-feature privileges for the feature. + const knownPrivileges = new Map(collectSubFeaturesPrivileges(feature)); + if (knownPrivileges.size === 0) { + throw new Error( + `Cannot override sub-feature privileges of feature "${featureId}" since it didn't register any.` + ); + } + + for (const [privilegeId, privilegeOverride] of Object.entries( + featureOverride.subFeatures.privileges + )) { + const targetPrivilege = knownPrivileges.get(privilegeId); + if (!targetPrivilege) { + throw new Error( + `Cannot override sub-feature privilege "${privilegeId}" of feature "${featureId}" since "${privilegeId}" sub-feature privilege is not registered. Known sub-feature privileges are: ${Array.from( + knownPrivileges.keys() + )}.` + ); + } + + targetPrivilege.disabled = privilegeOverride.disabled; + if (privilegeOverride.includeIn) { + targetPrivilege.includeIn = privilegeOverride.includeIn; + } + } + } + } + } + public getAllKibanaFeatures(license?: ILicense, ignoreLicense = false): KibanaFeature[] { if (!this.locked) { throw new Error('Cannot retrieve Kibana features while registration is still open'); @@ -143,3 +246,15 @@ function applyAutomaticReadPrivilegeGrants( } }); } + +function collectSubFeaturesPrivileges(feature: KibanaFeatureConfig) { + return ( + feature.subFeatures?.flatMap((subFeature) => + subFeature.privilegeGroups.flatMap(({ privileges }) => + privileges.map( + (privilege) => [privilege.id, privilege] as [string, SubFeaturePrivilegeConfig] + ) + ) + ) ?? [] + ); +} diff --git a/x-pack/plugins/features/server/feature_schema.ts b/x-pack/plugins/features/server/feature_schema.ts index b332ea355dcc0..341bb926b277d 100644 --- a/x-pack/plugins/features/server/feature_schema.ts +++ b/x-pack/plugins/features/server/feature_schema.ts @@ -187,6 +187,8 @@ const kibanaSubFeatureSchema = schema.object({ ), }); +// NOTE: This schema intentionally omits the `composedOf` and `hidden` properties to discourage consumers from using +// them during feature registration. This is because these properties should only be set via configuration overrides. const kibanaFeatureSchema = schema.object({ id: schema.string({ validate(value: string) { diff --git a/x-pack/plugins/features/server/index.ts b/x-pack/plugins/features/server/index.ts index b40094dee92d4..48c292515ed27 100644 --- a/x-pack/plugins/features/server/index.ts +++ b/x-pack/plugins/features/server/index.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { PluginInitializerContext } from '@kbn/core/server'; +import type { PluginConfigDescriptor, PluginInitializerContext } from '@kbn/core/server'; +import type { TypeOf } from '@kbn/config-schema'; +import { ConfigSchema } from './config'; // These exports are part of public Features plugin contract, any change in signature of exported // functions or removal of exports should be considered as a breaking change. Ideally we should @@ -22,6 +24,7 @@ export type { export { KibanaFeature, ElasticsearchFeature } from '../common'; export type { PluginSetupContract, PluginStartContract } from './plugin'; +export const config: PluginConfigDescriptor> = { schema: ConfigSchema }; export const plugin = async (initializerContext: PluginInitializerContext) => { const { FeaturesPlugin } = await import('./plugin'); return new FeaturesPlugin(initializerContext); diff --git a/x-pack/plugins/features/server/plugin.test.ts b/x-pack/plugins/features/server/plugin.test.ts index ca88da0458846..d353ee0588d5f 100644 --- a/x-pack/plugins/features/server/plugin.test.ts +++ b/x-pack/plugins/features/server/plugin.test.ts @@ -6,6 +6,7 @@ */ import { coreMock, savedObjectsServiceMock } from '@kbn/core/server/mocks'; +import { ConfigSchema } from './config'; import { FeaturesPlugin } from './plugin'; describe('Features Plugin', () => { @@ -120,4 +121,76 @@ describe('Features Plugin', () => { expect(coreSetup.capabilities.registerProvider).toHaveBeenCalledTimes(1); expect(coreSetup.capabilities.registerProvider).toHaveBeenCalledWith(expect.any(Function)); }); + + it('apply feature overrides', async () => { + const plugin = new FeaturesPlugin( + coreMock.createPluginInitializerContext( + ConfigSchema.validate( + { overrides: { featureA: { name: 'overriddenFeatureName', order: 321 } } }, + { serverless: true } + ) + ) + ); + const { registerKibanaFeature } = plugin.setup(coreSetup); + registerKibanaFeature({ + id: 'featureA', + name: 'featureAName', + app: [], + category: { id: 'foo', label: 'foo' }, + order: 123, + privileges: { + all: { savedObject: { all: ['one'], read: ['two'] }, ui: [] }, + read: { savedObject: { all: ['three'], read: ['four'] }, ui: [] }, + }, + }); + + const { getKibanaFeatures } = plugin.start(coreStart); + expect(getKibanaFeatures().find((feature) => feature.id === 'featureA')).toMatchInlineSnapshot(` + KibanaFeature { + "config": Object { + "app": Array [], + "category": Object { + "id": "foo", + "label": "foo", + }, + "id": "featureA", + "name": "overriddenFeatureName", + "order": 321, + "privileges": Object { + "all": Object { + "savedObject": Object { + "all": Array [ + "one", + "telemetry", + ], + "read": Array [ + "two", + "config", + "config-global", + "url", + ], + }, + "ui": Array [], + }, + "read": Object { + "savedObject": Object { + "all": Array [ + "three", + ], + "read": Array [ + "four", + "config", + "config-global", + "telemetry", + "url", + ], + }, + "ui": Array [], + }, + }, + }, + "subFeatures": Array [], + } + `); + }); }); diff --git a/x-pack/plugins/features/server/plugin.ts b/x-pack/plugins/features/server/plugin.ts index b396dc9a17972..c6e8cdd96556c 100644 --- a/x-pack/plugins/features/server/plugin.ts +++ b/x-pack/plugins/features/server/plugin.ts @@ -16,6 +16,7 @@ import { PluginInitializerContext, Capabilities as UICapabilities, } from '@kbn/core/server'; +import { ConfigType } from './config'; import { FeatureRegistry } from './feature_registry'; import { uiCapabilitiesForFeatures } from './ui_capabilities_for_features'; import { buildOSSFeatures } from './oss_features'; @@ -127,6 +128,12 @@ export class FeaturesPlugin public start(core: CoreStart): RecursiveReadonly { this.registerOssFeatures(core.savedObjects); + + const { overrides } = this.initializerContext.config.get(); + if (overrides) { + this.featureRegistry.applyOverrides(overrides); + } + this.featureRegistry.lockRegistration(); this.capabilities = uiCapabilitiesForFeatures( diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index 5a2b8c1533396..112b08e70df2a 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -8,7 +8,7 @@ import * as Rx from 'rxjs'; import { map, take } from 'rxjs'; -import type { +import { AnalyticsServiceStart, CoreSetup, DocLinksServiceSetup, @@ -237,41 +237,6 @@ export class ReportingCore { return exportTypes; } - /** - * If xpack.reporting.roles.enabled === true, register Reporting as a feature - * that is controlled by user role names - */ - public registerFeature() { - const { features } = this.getPluginSetupDeps(); - const deprecatedRoles = this.getDeprecatedAllowedRoles(); - - if (deprecatedRoles !== false) { - // refer to roles.allow configuration (deprecated path) - const allowedRoles = ['superuser', ...(deprecatedRoles ?? [])]; - const privileges = allowedRoles.map((role) => ({ - requiredClusterPrivileges: [], - requiredRoles: [role], - ui: [], - })); - - // self-register as an elasticsearch feature (deprecated) - features.registerElasticsearchFeature({ - id: 'reporting', - catalogue: ['reporting'], - management: { - insightsAndAlerting: ['reporting'], - }, - privileges, - }); - } else { - this.logger.debug( - `Reporting roles configuration is disabled. Please assign access to Reporting use Kibana feature controls for applications.` - ); - // trigger application to register Reporting as a subfeature - features.enableReportingUiCapabilities(); - } - } - /* * Returns configurable server info */ diff --git a/x-pack/plugins/reporting/server/features.ts b/x-pack/plugins/reporting/server/features.ts new file mode 100644 index 0000000000000..45666e2b2460d --- /dev/null +++ b/x-pack/plugins/reporting/server/features.ts @@ -0,0 +1,74 @@ +/* + * 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 { DEFAULT_APP_CATEGORIES, type Logger } from '@kbn/core/server'; +import { i18n } from '@kbn/i18n'; +import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; + +interface FeatureRegistrationOpts { + features: FeaturesPluginSetup; + deprecatedRoles: string[] | false; + isServerless: boolean; + logger: Logger; +} + +/** + * If xpack.reporting.roles.enabled === true, register Reporting as a feature + * that is controlled by user role names. Also, for Serverless register a + * 'shell' Reporting Kibana feature. + */ +export function registerFeatures({ + isServerless, + features, + deprecatedRoles, + logger, +}: FeatureRegistrationOpts) { + // Register a 'shell' feature specifically for Serverless. If granted, it will automatically provide access to + // reporting capabilities in other features, such as Discover, Dashboards, and Visualizations. On its own, this + // feature doesn't grant any additional privileges. + if (isServerless) { + features.registerKibanaFeature({ + id: 'reporting', + name: i18n.translate('xpack.reporting.features.reportingFeatureName', { + defaultMessage: 'Reporting', + }), + category: DEFAULT_APP_CATEGORIES.management, + app: [], + privileges: { + all: { savedObject: { all: [], read: [] }, ui: [] }, + // No read-only mode currently supported + read: { disabled: true, savedObject: { all: [], read: [] }, ui: [] }, + }, + }); + } + + if (deprecatedRoles !== false) { + // refer to roles.allow configuration (deprecated path) + const allowedRoles = ['superuser', ...(deprecatedRoles ?? [])]; + const privileges = allowedRoles.map((role) => ({ + requiredClusterPrivileges: [], + requiredRoles: [role], + ui: [], + })); + + // self-register as an elasticsearch feature (deprecated) + features.registerElasticsearchFeature({ + id: 'reporting', + catalogue: ['reporting'], + management: { + insightsAndAlerting: ['reporting'], + }, + privileges, + }); + } else { + logger.debug( + `Reporting roles configuration is disabled. Please assign access to Reporting use Kibana feature controls for applications.` + ); + // trigger application to register Reporting as a subfeature + features.enableReportingUiCapabilities(); + } +} diff --git a/x-pack/plugins/reporting/server/plugin.test.ts b/x-pack/plugins/reporting/server/plugin.test.ts index 8e1149b5d80f6..4abb64dc13e8b 100644 --- a/x-pack/plugins/reporting/server/plugin.test.ts +++ b/x-pack/plugins/reporting/server/plugin.test.ts @@ -5,8 +5,15 @@ * 2.0. */ -import type { CoreSetup, CoreStart, Logger } from '@kbn/core/server'; +import { + CoreSetup, + CoreStart, + DEFAULT_APP_CATEGORIES, + Logger, + type PackageInfo, +} from '@kbn/core/server'; import { coreMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { createMockConfigSchema } from '@kbn/reporting-mocks-server'; import { CSV_REPORT_TYPE, CSV_REPORT_TYPE_V2 } from '@kbn/reporting-export-types-csv-common'; @@ -18,6 +25,7 @@ import { ReportingPlugin } from './plugin'; import { createMockPluginSetup, createMockPluginStart } from './test_helpers'; import type { ReportingSetupDeps } from './types'; import { ExportTypesRegistry } from '@kbn/reporting-server/export_types_registry'; +import { PluginSetupContract as FeaturesPluginSetupContract } from '@kbn/features-plugin/server'; const sleep = (time: number) => new Promise((r) => setTimeout(r, time)); @@ -30,6 +38,7 @@ describe('Reporting Plugin', () => { let pluginStart: ReportingInternalStart; let logger: jest.Mocked; let plugin: ReportingPlugin; + let featuresSetup: jest.Mocked; beforeEach(async () => { jest.clearAllMocks(); @@ -38,7 +47,10 @@ describe('Reporting Plugin', () => { initContext = coreMock.createPluginInitializerContext(configSchema); coreSetup = coreMock.createSetup(configSchema); coreStart = coreMock.createStart(); - pluginSetup = createMockPluginSetup({}) as unknown as ReportingSetupDeps; + featuresSetup = featuresPluginMock.createSetup(); + pluginSetup = createMockPluginSetup({ + features: featuresSetup, + }) as unknown as ReportingSetupDeps; pluginStart = await createMockPluginStart(coreStart, configSchema); logger = loggingSystemMock.createLogger(); @@ -143,4 +155,33 @@ describe('Reporting Plugin', () => { ); }); }); + + describe('features registration', () => { + it('does not register Kibana reporting feature in traditional build flavour', async () => { + plugin.setup(coreSetup, pluginSetup); + expect(featuresSetup.registerKibanaFeature).not.toHaveBeenCalled(); + expect(featuresSetup.enableReportingUiCapabilities).toHaveBeenCalledTimes(1); + }); + + it('registers Kibana reporting feature in serverless build flavour', async () => { + const serverlessInitContext = coreMock.createPluginInitializerContext(configSchema); + // Force type-cast to convert `ReadOnly` to mutable `PackageInfo`. + (serverlessInitContext.env.packageInfo as PackageInfo).buildFlavor = 'serverless'; + plugin = new ReportingPlugin(serverlessInitContext); + + plugin.setup(coreSetup, pluginSetup); + expect(featuresSetup.registerKibanaFeature).toHaveBeenCalledTimes(1); + expect(featuresSetup.registerKibanaFeature).toHaveBeenCalledWith({ + id: 'reporting', + name: 'Reporting', + category: DEFAULT_APP_CATEGORIES.management, + app: [], + privileges: { + all: { savedObject: { all: [], read: [] }, ui: [] }, + read: { disabled: true, savedObject: { all: [], read: [] }, ui: [] }, + }, + }); + expect(featuresSetup.enableReportingUiCapabilities).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index ea4722ef5c30e..3e68310f76cf4 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -26,6 +26,7 @@ import type { } from './types'; import { ReportingRequestHandlerContext } from './types'; import { registerReportingEventTypes, registerReportingUsageCollector } from './usage'; +import { registerFeatures } from './features'; /* * @internal @@ -79,8 +80,13 @@ export class ReportingPlugin // async background setup (async () => { - // Feature registration relies on config, so it cannot be setup before here. - reportingCore.registerFeature(); + // Feature registration relies on config, depending on whether deprecated roles are enabled, so it cannot be setup before here. + registerFeatures({ + features: plugins.features, + deprecatedRoles: reportingCore.getDeprecatedAllowedRoles(), + isServerless: this.initContext.env.packageInfo.buildFlavor === 'serverless', + logger: this.logger, + }); this.logger.debug('Setup complete'); })().catch((e) => { this.logger.error(`Error in Reporting setup, reporting may not function properly`); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx index 36e6a5782f784..ccdc71d119f08 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx @@ -308,7 +308,7 @@ function useFeatures( fatalErrors.add(err); }) .then((retrievedFeatures) => { - setFeatures(retrievedFeatures); + setFeatures(retrievedFeatures?.filter((feature) => !feature.hidden) ?? null); }); }, [fatalErrors, getFeatures]); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx index 90f26eee5a930..03ed9597fcb2d 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx @@ -36,9 +36,7 @@ interface Props { } export const SubFeatureForm = (props: Props) => { - const groupsWithPrivileges = props.subFeature - .getPrivilegeGroups() - .filter((group) => group.privileges.length > 0); + const groupsWithPrivileges = props.subFeature.getPrivilegeGroups(); const getTooltip = () => { if (!props.subFeature.privilegesTooltip) { diff --git a/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts b/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts index 79e98625cb06f..11ac512cd5a18 100644 --- a/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts +++ b/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { SubFeatureConfig } from '@kbn/features-plugin/common'; +import type { SubFeatureConfig, SubFeaturePrivilegeGroupConfig } from '@kbn/features-plugin/common'; import { SubFeature } from '@kbn/features-plugin/common'; import { SubFeaturePrivilege } from './sub_feature_privilege'; @@ -14,6 +14,10 @@ import { SubFeaturePrivilegeGroup } from './sub_feature_privilege_group'; export class SecuredSubFeature extends SubFeature { public readonly privileges: SubFeaturePrivilege[]; public readonly privilegesTooltip: string; + /** + * A list of the privilege groups that have at least one enabled privilege. + */ + private readonly nonEmptyPrivilegeGroups: SubFeaturePrivilegeGroupConfig[]; constructor( config: SubFeatureConfig, @@ -23,14 +27,27 @@ export class SecuredSubFeature extends SubFeature { this.privilegesTooltip = config.privilegesTooltip || ''; - this.privileges = []; - for (const privilege of this.privilegeIterator()) { - this.privileges.push(privilege); - } + this.nonEmptyPrivilegeGroups = this.privilegeGroups.flatMap((group) => { + const filteredPrivileges = group.privileges.filter((privilege) => !privilege.disabled); + if (filteredPrivileges.length === 0) { + return []; + } + + // If some privileges are disabled, we need to update the group to reflect the change. + return [ + group.privileges.length === filteredPrivileges.length + ? group + : ({ ...group, privileges: filteredPrivileges } as SubFeaturePrivilegeGroupConfig), + ]; + }); + + this.privileges = Array.from(this.privilegeIterator()); } public getPrivilegeGroups() { - return this.privilegeGroups.map((pg) => new SubFeaturePrivilegeGroup(pg, this.actionMapping)); + return this.nonEmptyPrivilegeGroups.map( + (pg) => new SubFeaturePrivilegeGroup(pg, this.actionMapping) + ); } public *privilegeIterator({ @@ -38,10 +55,13 @@ export class SecuredSubFeature extends SubFeature { }: { predicate?: (privilege: SubFeaturePrivilege, feature: SecuredSubFeature) => boolean; } = {}): IterableIterator { - for (const group of this.privilegeGroups) { - yield* group.privileges - .map((gp) => new SubFeaturePrivilege(gp, this.actionMapping[gp.id])) - .filter((privilege) => predicate(privilege, this)); + for (const group of this.nonEmptyPrivilegeGroups) { + for (const gp of group.privileges) { + const privilege = new SubFeaturePrivilege(gp, this.actionMapping[gp.id]); + if (predicate(privilege, this)) { + yield privilege; + } + } } } diff --git a/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts b/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts index b5897654a6a38..e9b58ba8b2294 100644 --- a/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts +++ b/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts @@ -21,6 +21,10 @@ export class SubFeaturePrivilege extends KibanaPrivilege { return this.subPrivilegeConfig.name; } + public get disabled() { + return this.subPrivilegeConfig.disabled; + } + public get requireAllSpaces() { return this.subPrivilegeConfig.requireAllSpaces ?? false; } diff --git a/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts b/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts index e27a30ae42445..93efd86f52f54 100644 --- a/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts @@ -185,6 +185,293 @@ describe('features', () => { }); }); + test('actions should respect `composedOf` specified at the privilege', () => { + const features: KibanaFeature[] = [ + new KibanaFeature({ + id: 'foo', + name: 'Foo KibanaFeature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: { + savedObject: { + all: ['all-savedObject-all-1'], + read: ['all-savedObject-read-1'], + }, + ui: ['all-ui-1'], + }, + read: { + savedObject: { + all: ['read-savedObject-all-1'], + read: ['read-savedObject-read-1'], + }, + ui: ['read-ui-1'], + }, + }, + }), + new KibanaFeature({ + id: 'bar', + name: 'Bar KibanaFeature', + app: [], + category: { id: 'bar', label: 'bar' }, + privileges: { + all: { + savedObject: { + all: ['all-savedObject-all-2'], + read: ['all-savedObject-read-2'], + }, + ui: ['all-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['all'] }], + }, + read: { + savedObject: { + all: ['read-savedObject-all-2'], + read: ['read-savedObject-read-2'], + }, + ui: ['read-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['read'] }], + }, + }, + }), + ]; + + const mockFeaturesPlugin = featuresPluginMock.createSetup(); + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features); + const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic); + + const expectedAllPrivileges = [ + actions.login, + actions.savedObject.get('all-savedObject-all-2', 'bulk_get'), + actions.savedObject.get('all-savedObject-all-2', 'get'), + actions.savedObject.get('all-savedObject-all-2', 'find'), + actions.savedObject.get('all-savedObject-all-2', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-all-2', 'close_point_in_time'), + actions.savedObject.get('all-savedObject-all-2', 'create'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_create'), + actions.savedObject.get('all-savedObject-all-2', 'update'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_update'), + actions.savedObject.get('all-savedObject-all-2', 'delete'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_delete'), + actions.savedObject.get('all-savedObject-all-2', 'share_to_space'), + actions.savedObject.get('all-savedObject-read-2', 'bulk_get'), + actions.savedObject.get('all-savedObject-read-2', 'get'), + actions.savedObject.get('all-savedObject-read-2', 'find'), + actions.savedObject.get('all-savedObject-read-2', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-read-2', 'close_point_in_time'), + actions.ui.get('bar', 'all-ui-2'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_get'), + actions.savedObject.get('all-savedObject-all-1', 'get'), + actions.savedObject.get('all-savedObject-all-1', 'find'), + actions.savedObject.get('all-savedObject-all-1', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-all-1', 'close_point_in_time'), + actions.savedObject.get('all-savedObject-all-1', 'create'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_create'), + actions.savedObject.get('all-savedObject-all-1', 'update'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_update'), + actions.savedObject.get('all-savedObject-all-1', 'delete'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_delete'), + actions.savedObject.get('all-savedObject-all-1', 'share_to_space'), + actions.savedObject.get('all-savedObject-read-1', 'bulk_get'), + actions.savedObject.get('all-savedObject-read-1', 'get'), + actions.savedObject.get('all-savedObject-read-1', 'find'), + actions.savedObject.get('all-savedObject-read-1', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-read-1', 'close_point_in_time'), + actions.ui.get('foo', 'all-ui-1'), + ]; + + const expectedReadPrivileges = [ + actions.login, + actions.savedObject.get('read-savedObject-all-2', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-2', 'get'), + actions.savedObject.get('read-savedObject-all-2', 'find'), + actions.savedObject.get('read-savedObject-all-2', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-2', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-2', 'create'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-2', 'update'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-2', 'delete'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-2', 'share_to_space'), + actions.savedObject.get('read-savedObject-read-2', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-2', 'get'), + actions.savedObject.get('read-savedObject-read-2', 'find'), + actions.savedObject.get('read-savedObject-read-2', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-2', 'close_point_in_time'), + actions.ui.get('bar', 'read-ui-2'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-1', 'get'), + actions.savedObject.get('read-savedObject-all-1', 'find'), + actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'create'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-1', 'update'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-1', 'delete'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-1', 'share_to_space'), + actions.savedObject.get('read-savedObject-read-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-1', 'get'), + actions.savedObject.get('read-savedObject-read-1', 'find'), + actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'), + actions.ui.get('foo', 'read-ui-1'), + ]; + + const actual = privileges.get(); + expect(actual).toHaveProperty('features.bar', { + all: [...expectedAllPrivileges], + read: [...expectedReadPrivileges], + minimal_all: [...expectedAllPrivileges], + minimal_read: [...expectedReadPrivileges], + }); + }); + + test('actions should respect `composedOf` specified at the privilege even if the referenced feature is hidden', () => { + const features: KibanaFeature[] = [ + new KibanaFeature({ + hidden: true, + id: 'foo', + name: 'Foo KibanaFeature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: { + savedObject: { + all: ['all-savedObject-all-1'], + read: ['all-savedObject-read-1'], + }, + ui: ['all-ui-1'], + }, + read: { + savedObject: { + all: ['read-savedObject-all-1'], + read: ['read-savedObject-read-1'], + }, + ui: ['read-ui-1'], + }, + }, + }), + new KibanaFeature({ + id: 'bar', + name: 'Bar KibanaFeature', + app: [], + category: { id: 'bar', label: 'bar' }, + privileges: { + all: { + savedObject: { + all: ['all-savedObject-all-2'], + read: ['all-savedObject-read-2'], + }, + ui: ['all-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['all'] }], + }, + read: { + savedObject: { + all: ['read-savedObject-all-2'], + read: ['read-savedObject-read-2'], + }, + ui: ['read-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['read'] }], + }, + }, + }), + ]; + + const mockFeaturesPlugin = featuresPluginMock.createSetup(); + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features); + const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic); + + const expectedAllPrivileges = [ + actions.login, + actions.savedObject.get('all-savedObject-all-2', 'bulk_get'), + actions.savedObject.get('all-savedObject-all-2', 'get'), + actions.savedObject.get('all-savedObject-all-2', 'find'), + actions.savedObject.get('all-savedObject-all-2', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-all-2', 'close_point_in_time'), + actions.savedObject.get('all-savedObject-all-2', 'create'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_create'), + actions.savedObject.get('all-savedObject-all-2', 'update'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_update'), + actions.savedObject.get('all-savedObject-all-2', 'delete'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_delete'), + actions.savedObject.get('all-savedObject-all-2', 'share_to_space'), + actions.savedObject.get('all-savedObject-read-2', 'bulk_get'), + actions.savedObject.get('all-savedObject-read-2', 'get'), + actions.savedObject.get('all-savedObject-read-2', 'find'), + actions.savedObject.get('all-savedObject-read-2', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-read-2', 'close_point_in_time'), + actions.ui.get('bar', 'all-ui-2'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_get'), + actions.savedObject.get('all-savedObject-all-1', 'get'), + actions.savedObject.get('all-savedObject-all-1', 'find'), + actions.savedObject.get('all-savedObject-all-1', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-all-1', 'close_point_in_time'), + actions.savedObject.get('all-savedObject-all-1', 'create'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_create'), + actions.savedObject.get('all-savedObject-all-1', 'update'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_update'), + actions.savedObject.get('all-savedObject-all-1', 'delete'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_delete'), + actions.savedObject.get('all-savedObject-all-1', 'share_to_space'), + actions.savedObject.get('all-savedObject-read-1', 'bulk_get'), + actions.savedObject.get('all-savedObject-read-1', 'get'), + actions.savedObject.get('all-savedObject-read-1', 'find'), + actions.savedObject.get('all-savedObject-read-1', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-read-1', 'close_point_in_time'), + actions.ui.get('foo', 'all-ui-1'), + ]; + + const expectedReadPrivileges = [ + actions.login, + actions.savedObject.get('read-savedObject-all-2', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-2', 'get'), + actions.savedObject.get('read-savedObject-all-2', 'find'), + actions.savedObject.get('read-savedObject-all-2', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-2', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-2', 'create'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-2', 'update'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-2', 'delete'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-2', 'share_to_space'), + actions.savedObject.get('read-savedObject-read-2', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-2', 'get'), + actions.savedObject.get('read-savedObject-read-2', 'find'), + actions.savedObject.get('read-savedObject-read-2', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-2', 'close_point_in_time'), + actions.ui.get('bar', 'read-ui-2'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-1', 'get'), + actions.savedObject.get('read-savedObject-all-1', 'find'), + actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'create'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-1', 'update'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-1', 'delete'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-1', 'share_to_space'), + actions.savedObject.get('read-savedObject-read-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-1', 'get'), + actions.savedObject.get('read-savedObject-read-1', 'find'), + actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'), + actions.ui.get('foo', 'read-ui-1'), + ]; + + const actual = privileges.get(); + expect(actual).toHaveProperty('features.bar', { + all: [...expectedAllPrivileges], + read: [...expectedReadPrivileges], + minimal_all: [...expectedAllPrivileges], + minimal_read: [...expectedReadPrivileges], + }); + }); + test(`features with no privileges aren't listed`, () => { const features: KibanaFeature[] = [ new KibanaFeature({ @@ -192,7 +479,50 @@ describe('features', () => { name: 'Foo KibanaFeature', app: [], category: { id: 'foo', label: 'foo' }, - privileges: null, + privileges: null, + }), + ]; + + const mockFeaturesPlugin = featuresPluginMock.createSetup(); + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features); + const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic); + + const actual = privileges.get(); + expect(actual).not.toHaveProperty('features.foo'); + }); + + test(`hidden features aren't listed`, () => { + const features: KibanaFeature[] = [ + new KibanaFeature({ + hidden: true, + id: 'foo', + name: 'Foo KibanaFeature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: { + management: { + 'all-management': ['all-management-1'], + }, + catalogue: ['all-catalogue-1'], + savedObject: { + all: ['all-savedObject-all-1'], + read: ['all-savedObject-read-1'], + }, + ui: ['all-ui-1'], + }, + read: { + management: { + 'read-management': ['read-management-1'], + }, + catalogue: ['read-catalogue-1'], + savedObject: { + all: ['read-savedObject-all-1'], + read: ['read-savedObject-read-1'], + }, + ui: ['read-ui-1'], + }, + }, }), ]; @@ -202,6 +532,12 @@ describe('features', () => { const actual = privileges.get(); expect(actual).not.toHaveProperty('features.foo'); + + const checkPredicate = (action: string) => action.includes('all-') || action.includes('read-'); + expect(actual.global.all.some(checkPredicate)).toBe(false); + expect(actual.global.read.some(checkPredicate)).toBe(false); + expect(actual.space.all.some(checkPredicate)).toBe(false); + expect(actual.space.read.some(checkPredicate)).toBe(false); }); }); @@ -377,69 +713,362 @@ describe('features', () => { ]); }); - test('actions defined in a feature privilege with name `read` are included in `read`', () => { - const features: KibanaFeature[] = [ + test('actions defined in any feature privilege of a hidden but referenced feature are included in `all`, ignoring the excludeFromBasePrivileges property', () => { + const getFeatures = ({ + excludeFromBasePrivileges, + }: { + excludeFromBasePrivileges: boolean; + }) => [ + new KibanaFeature({ + hidden: true, + excludeFromBasePrivileges, + id: 'foo', + name: 'Foo KibanaFeature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: { + management: { + 'all-management': ['all-management-1'], + }, + catalogue: ['all-catalogue-1'], + savedObject: { + all: ['all-savedObject-all-1'], + read: ['all-savedObject-read-1'], + }, + ui: ['all-ui-1'], + }, + read: { + management: { + 'read-management': ['read-management-1'], + }, + catalogue: ['read-catalogue-1'], + savedObject: { + all: ['read-savedObject-all-1'], + read: ['read-savedObject-read-1'], + }, + ui: ['read-ui-1'], + }, + }, + }), + new KibanaFeature({ + id: 'bar', + name: 'Bar KibanaFeature', + app: [], + category: { id: 'bar', label: 'bar' }, + privileges: { + all: { + management: { + 'all-management': ['all-management-2'], + }, + catalogue: ['all-catalogue-2'], + savedObject: { + all: ['all-savedObject-all-2'], + read: ['all-savedObject-read-2'], + }, + ui: ['all-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['all'] }], + }, + read: { + management: { + 'read-management': ['read-management-2'], + }, + catalogue: ['read-catalogue-2'], + savedObject: { + all: ['read-savedObject-all-2'], + read: ['read-savedObject-read-2'], + }, + ui: ['read-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['read'] }], + }, + }, + }), + ]; + + const expectedActions = [ + actions.login, + ...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []), + ...(expectGetFeatures ? [actions.api.get('features')] : []), + ...(expectGetFeatures ? [actions.api.get('taskManager')] : []), + ...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []), + ...(expectManageSpaces + ? [ + actions.space.manage, + actions.ui.get('spaces', 'manage'), + actions.ui.get('management', 'kibana', 'spaces'), + actions.ui.get('catalogue', 'spaces'), + ] + : []), + ...(expectEnterpriseSearch ? [actions.ui.get('enterpriseSearch', 'all')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'save')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []), + actions.ui.get('catalogue', 'all-catalogue-2'), + actions.ui.get('management', 'all-management', 'all-management-2'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_get'), + actions.savedObject.get('all-savedObject-all-2', 'get'), + actions.savedObject.get('all-savedObject-all-2', 'find'), + actions.savedObject.get('all-savedObject-all-2', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-all-2', 'close_point_in_time'), + actions.savedObject.get('all-savedObject-all-2', 'create'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_create'), + actions.savedObject.get('all-savedObject-all-2', 'update'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_update'), + actions.savedObject.get('all-savedObject-all-2', 'delete'), + actions.savedObject.get('all-savedObject-all-2', 'bulk_delete'), + actions.savedObject.get('all-savedObject-all-2', 'share_to_space'), + actions.savedObject.get('all-savedObject-read-2', 'bulk_get'), + actions.savedObject.get('all-savedObject-read-2', 'get'), + actions.savedObject.get('all-savedObject-read-2', 'find'), + actions.savedObject.get('all-savedObject-read-2', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-read-2', 'close_point_in_time'), + actions.ui.get('bar', 'all-ui-2'), + actions.ui.get('catalogue', 'read-catalogue-2'), + actions.ui.get('management', 'read-management', 'read-management-2'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-2', 'get'), + actions.savedObject.get('read-savedObject-all-2', 'find'), + actions.savedObject.get('read-savedObject-all-2', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-2', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-2', 'create'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-2', 'update'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-2', 'delete'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-2', 'share_to_space'), + actions.savedObject.get('read-savedObject-read-2', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-2', 'get'), + actions.savedObject.get('read-savedObject-read-2', 'find'), + actions.savedObject.get('read-savedObject-read-2', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-2', 'close_point_in_time'), + actions.ui.get('bar', 'read-ui-2'), + actions.ui.get('catalogue', 'all-catalogue-1'), + actions.ui.get('management', 'all-management', 'all-management-1'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_get'), + actions.savedObject.get('all-savedObject-all-1', 'get'), + actions.savedObject.get('all-savedObject-all-1', 'find'), + actions.savedObject.get('all-savedObject-all-1', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-all-1', 'close_point_in_time'), + actions.savedObject.get('all-savedObject-all-1', 'create'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_create'), + actions.savedObject.get('all-savedObject-all-1', 'update'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_update'), + actions.savedObject.get('all-savedObject-all-1', 'delete'), + actions.savedObject.get('all-savedObject-all-1', 'bulk_delete'), + actions.savedObject.get('all-savedObject-all-1', 'share_to_space'), + actions.savedObject.get('all-savedObject-read-1', 'bulk_get'), + actions.savedObject.get('all-savedObject-read-1', 'get'), + actions.savedObject.get('all-savedObject-read-1', 'find'), + actions.savedObject.get('all-savedObject-read-1', 'open_point_in_time'), + actions.savedObject.get('all-savedObject-read-1', 'close_point_in_time'), + actions.ui.get('foo', 'all-ui-1'), + actions.ui.get('catalogue', 'read-catalogue-1'), + actions.ui.get('management', 'read-management', 'read-management-1'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-1', 'get'), + actions.savedObject.get('read-savedObject-all-1', 'find'), + actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'create'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-1', 'update'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-1', 'delete'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-1', 'share_to_space'), + actions.savedObject.get('read-savedObject-read-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-1', 'get'), + actions.savedObject.get('read-savedObject-read-1', 'find'), + actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'), + actions.ui.get('foo', 'read-ui-1'), + ]; + + const mockFeaturesPlugin = featuresPluginMock.createSetup(); + + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue( + getFeatures({ excludeFromBasePrivileges: false }) + ); + expect( + privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic).get() + ).toHaveProperty(`${group}.all`, expectedActions); + + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue( + getFeatures({ excludeFromBasePrivileges: true }) + ); + expect( + privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic).get() + ).toHaveProperty(`${group}.all`, expectedActions); + }); + + test('actions defined in a feature privilege with name `read` are included in `read`', () => { + const features: KibanaFeature[] = [ + new KibanaFeature({ + id: 'foo', + name: 'Foo KibanaFeature', + app: [], + category: { id: 'foo', label: 'foo' }, + catalogue: ['ignore-me-1', 'ignore-me-2'], + management: { + foo: ['ignore-me-1', 'ignore-me-2'], + }, + privileges: { + all: { + management: { + 'ignore-me': ['ignore-me-1', 'ignore-me-2'], + }, + catalogue: ['ignore-me-1', 'ignore-me-2'], + savedObject: { + all: ['ignore-me-1', 'ignore-me-2'], + read: ['ignore-me-1', 'ignore-me-2'], + }, + ui: ['ignore-me-1', 'ignore-me-2'], + }, + read: { + management: { + 'read-management': ['read-management-1', 'read-management-2'], + }, + catalogue: ['read-catalogue-1', 'read-catalogue-2'], + savedObject: { + all: ['read-savedObject-all-1', 'read-savedObject-all-2'], + read: ['read-savedObject-read-1', 'read-savedObject-read-2'], + }, + ui: ['read-ui-1', 'read-ui-2'], + }, + }, + }), + ]; + + const mockFeaturesPlugin = featuresPluginMock.createSetup(); + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features); + const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic); + + const actual = privileges.get(); + expect(actual).toHaveProperty(`${group}.read`, [ + actions.login, + ...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []), + actions.ui.get('catalogue', 'read-catalogue-1'), + actions.ui.get('catalogue', 'read-catalogue-2'), + actions.ui.get('management', 'read-management', 'read-management-1'), + actions.ui.get('management', 'read-management', 'read-management-2'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-1', 'get'), + actions.savedObject.get('read-savedObject-all-1', 'find'), + actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'create'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-1', 'update'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-1', 'delete'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-1', 'share_to_space'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-2', 'get'), + actions.savedObject.get('read-savedObject-all-2', 'find'), + actions.savedObject.get('read-savedObject-all-2', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-2', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-2', 'create'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-2', 'update'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-2', 'delete'), + actions.savedObject.get('read-savedObject-all-2', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-2', 'share_to_space'), + actions.savedObject.get('read-savedObject-read-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-1', 'get'), + actions.savedObject.get('read-savedObject-read-1', 'find'), + actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-read-2', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-2', 'get'), + actions.savedObject.get('read-savedObject-read-2', 'find'), + actions.savedObject.get('read-savedObject-read-2', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-2', 'close_point_in_time'), + actions.ui.get('foo', 'read-ui-1'), + actions.ui.get('foo', 'read-ui-2'), + ]); + }); + + test('actions defined in a feature privilege with name `read` of a hidden but referenced feature are included in `read`, ignoring the excludeFromBasePrivileges property', () => { + const getFeatures = ({ + excludeFromBasePrivileges, + }: { + excludeFromBasePrivileges: boolean; + }) => [ new KibanaFeature({ + hidden: true, + excludeFromBasePrivileges, id: 'foo', name: 'Foo KibanaFeature', app: [], category: { id: 'foo', label: 'foo' }, - catalogue: ['ignore-me-1', 'ignore-me-2'], - management: { - foo: ['ignore-me-1', 'ignore-me-2'], + privileges: { + all: { + management: { + 'all-management': ['all-management-1'], + }, + catalogue: ['all-catalogue-1'], + savedObject: { + all: ['all-savedObject-all-1'], + read: ['all-savedObject-read-1'], + }, + ui: ['all-ui-1'], + }, + read: { + management: { + 'read-management': ['read-management-1'], + }, + catalogue: ['read-catalogue-1'], + savedObject: { + all: ['read-savedObject-all-1'], + read: ['read-savedObject-read-1'], + }, + ui: ['read-ui-1'], + }, }, + }), + new KibanaFeature({ + id: 'bar', + name: 'Bar KibanaFeature', + app: [], + category: { id: 'bar', label: 'bar' }, privileges: { all: { management: { - 'ignore-me': ['ignore-me-1', 'ignore-me-2'], + 'all-management': ['all-management-2'], }, - catalogue: ['ignore-me-1', 'ignore-me-2'], + catalogue: ['all-catalogue-2'], savedObject: { - all: ['ignore-me-1', 'ignore-me-2'], - read: ['ignore-me-1', 'ignore-me-2'], + all: ['all-savedObject-all-2'], + read: ['all-savedObject-read-2'], }, - ui: ['ignore-me-1', 'ignore-me-2'], + ui: ['all-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['all'] }], }, read: { management: { - 'read-management': ['read-management-1', 'read-management-2'], + 'read-management': ['read-management-2'], }, - catalogue: ['read-catalogue-1', 'read-catalogue-2'], + catalogue: ['read-catalogue-2'], savedObject: { - all: ['read-savedObject-all-1', 'read-savedObject-all-2'], - read: ['read-savedObject-read-1', 'read-savedObject-read-2'], + all: ['read-savedObject-all-2'], + read: ['read-savedObject-read-2'], }, - ui: ['read-ui-1', 'read-ui-2'], + ui: ['read-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['read'] }], }, }, }), ]; - const mockFeaturesPlugin = featuresPluginMock.createSetup(); - mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features); - const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic); - - const actual = privileges.get(); - expect(actual).toHaveProperty(`${group}.read`, [ + const expectedActions = [ actions.login, ...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []), ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []), - actions.ui.get('catalogue', 'read-catalogue-1'), actions.ui.get('catalogue', 'read-catalogue-2'), - actions.ui.get('management', 'read-management', 'read-management-1'), actions.ui.get('management', 'read-management', 'read-management-2'), - actions.savedObject.get('read-savedObject-all-1', 'bulk_get'), - actions.savedObject.get('read-savedObject-all-1', 'get'), - actions.savedObject.get('read-savedObject-all-1', 'find'), - actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'), - actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'), - actions.savedObject.get('read-savedObject-all-1', 'create'), - actions.savedObject.get('read-savedObject-all-1', 'bulk_create'), - actions.savedObject.get('read-savedObject-all-1', 'update'), - actions.savedObject.get('read-savedObject-all-1', 'bulk_update'), - actions.savedObject.get('read-savedObject-all-1', 'delete'), - actions.savedObject.get('read-savedObject-all-1', 'bulk_delete'), - actions.savedObject.get('read-savedObject-all-1', 'share_to_space'), actions.savedObject.get('read-savedObject-all-2', 'bulk_get'), actions.savedObject.get('read-savedObject-all-2', 'get'), actions.savedObject.get('read-savedObject-all-2', 'find'), @@ -452,19 +1081,49 @@ describe('features', () => { actions.savedObject.get('read-savedObject-all-2', 'delete'), actions.savedObject.get('read-savedObject-all-2', 'bulk_delete'), actions.savedObject.get('read-savedObject-all-2', 'share_to_space'), - actions.savedObject.get('read-savedObject-read-1', 'bulk_get'), - actions.savedObject.get('read-savedObject-read-1', 'get'), - actions.savedObject.get('read-savedObject-read-1', 'find'), - actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'), - actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'), actions.savedObject.get('read-savedObject-read-2', 'bulk_get'), actions.savedObject.get('read-savedObject-read-2', 'get'), actions.savedObject.get('read-savedObject-read-2', 'find'), actions.savedObject.get('read-savedObject-read-2', 'open_point_in_time'), actions.savedObject.get('read-savedObject-read-2', 'close_point_in_time'), + actions.ui.get('bar', 'read-ui-2'), + actions.ui.get('catalogue', 'read-catalogue-1'), + actions.ui.get('management', 'read-management', 'read-management-1'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-all-1', 'get'), + actions.savedObject.get('read-savedObject-all-1', 'find'), + actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'), + actions.savedObject.get('read-savedObject-all-1', 'create'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_create'), + actions.savedObject.get('read-savedObject-all-1', 'update'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_update'), + actions.savedObject.get('read-savedObject-all-1', 'delete'), + actions.savedObject.get('read-savedObject-all-1', 'bulk_delete'), + actions.savedObject.get('read-savedObject-all-1', 'share_to_space'), + actions.savedObject.get('read-savedObject-read-1', 'bulk_get'), + actions.savedObject.get('read-savedObject-read-1', 'get'), + actions.savedObject.get('read-savedObject-read-1', 'find'), + actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'), + actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'), actions.ui.get('foo', 'read-ui-1'), - actions.ui.get('foo', 'read-ui-2'), - ]); + ]; + + const mockFeaturesPlugin = featuresPluginMock.createSetup(); + + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue( + getFeatures({ excludeFromBasePrivileges: false }) + ); + expect( + privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic).get() + ).toHaveProperty(`${group}.read`, expectedActions); + + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue( + getFeatures({ excludeFromBasePrivileges: true }) + ); + expect( + privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic).get() + ).toHaveProperty(`${group}.read`, expectedActions); }); test('actions defined in a reserved privilege are not included in `all` or `read`', () => { @@ -596,6 +1255,104 @@ describe('features', () => { ]); }); + test('actions defined via `composedOf` in a feature with excludeFromBasePrivileges are not included in `all` or `read', () => { + const features: KibanaFeature[] = [ + new KibanaFeature({ + hidden: true, + id: 'foo', + name: 'Foo KibanaFeature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: { + management: { + 'all-management': ['all-management-1'], + }, + catalogue: ['all-catalogue-1'], + savedObject: { + all: ['all-savedObject-all-1'], + read: ['all-savedObject-read-1'], + }, + ui: ['all-ui-1'], + }, + read: { + management: { + 'read-management': ['read-management-1'], + }, + catalogue: ['read-catalogue-1'], + savedObject: { + all: ['read-savedObject-all-1'], + read: ['read-savedObject-read-1'], + }, + ui: ['read-ui-1'], + }, + }, + }), + new KibanaFeature({ + excludeFromBasePrivileges: true, + id: 'bar', + name: 'Bar KibanaFeature', + app: [], + category: { id: 'bar', label: 'bar' }, + privileges: { + all: { + management: { + 'all-management': ['all-management-2'], + }, + catalogue: ['all-catalogue-2'], + savedObject: { + all: ['all-savedObject-all-2'], + read: ['all-savedObject-read-2'], + }, + ui: ['all-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['all'] }], + }, + read: { + management: { + 'read-management': ['read-management-2'], + }, + catalogue: ['read-catalogue-2'], + savedObject: { + all: ['read-savedObject-all-2'], + read: ['read-savedObject-read-2'], + }, + ui: ['read-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['read'] }], + }, + }, + }), + ]; + + const mockFeaturesPlugin = featuresPluginMock.createSetup(); + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features); + const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic); + + const actual = privileges.get(); + expect(actual).toHaveProperty(`${group}.all`, [ + actions.login, + ...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []), + ...(expectGetFeatures ? [actions.api.get('features')] : []), + ...(expectGetFeatures ? [actions.api.get('taskManager')] : []), + ...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []), + ...(expectManageSpaces + ? [ + actions.space.manage, + actions.ui.get('spaces', 'manage'), + actions.ui.get('management', 'kibana', 'spaces'), + actions.ui.get('catalogue', 'spaces'), + ] + : []), + ...(expectEnterpriseSearch ? [actions.ui.get('enterpriseSearch', 'all')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'save')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []), + ]); + expect(actual).toHaveProperty(`${group}.read`, [ + actions.login, + ...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []), + ]); + }); + test('actions defined in an individual feature privilege with excludeFromBasePrivileges are not included in `all` or `read`', () => { const features: KibanaFeature[] = [ new KibanaFeature({ @@ -665,6 +1422,105 @@ describe('features', () => { ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []), ]); }); + + test('actions defined via `composedOf` in an individual feature privilege with excludeFromBasePrivileges are not included in `all` or `read`', () => { + const features: KibanaFeature[] = [ + new KibanaFeature({ + hidden: true, + id: 'foo', + name: 'Foo KibanaFeature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: { + management: { + 'all-management': ['all-management-1'], + }, + catalogue: ['all-catalogue-1'], + savedObject: { + all: ['all-savedObject-all-1'], + read: ['all-savedObject-read-1'], + }, + ui: ['all-ui-1'], + }, + read: { + management: { + 'read-management': ['read-management-1'], + }, + catalogue: ['read-catalogue-1'], + savedObject: { + all: ['read-savedObject-all-1'], + read: ['read-savedObject-read-1'], + }, + ui: ['read-ui-1'], + }, + }, + }), + new KibanaFeature({ + id: 'bar', + name: 'Bar KibanaFeature', + app: [], + category: { id: 'bar', label: 'bar' }, + privileges: { + all: { + excludeFromBasePrivileges: true, + management: { + 'all-management': ['all-management-2'], + }, + catalogue: ['all-catalogue-2'], + savedObject: { + all: ['all-savedObject-all-2'], + read: ['all-savedObject-read-2'], + }, + ui: ['all-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['all'] }], + }, + read: { + excludeFromBasePrivileges: true, + management: { + 'read-management': ['read-management-2'], + }, + catalogue: ['read-catalogue-2'], + savedObject: { + all: ['read-savedObject-all-2'], + read: ['read-savedObject-read-2'], + }, + ui: ['read-ui-2'], + composedOf: [{ feature: 'foo', privileges: ['read'] }], + }, + }, + }), + ]; + + const mockFeaturesPlugin = featuresPluginMock.createSetup(); + mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features); + const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic); + + const actual = privileges.get(); + expect(actual).toHaveProperty(`${group}.all`, [ + actions.login, + ...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []), + ...(expectGetFeatures ? [actions.api.get('features')] : []), + ...(expectGetFeatures ? [actions.api.get('taskManager')] : []), + ...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []), + ...(expectManageSpaces + ? [ + actions.space.manage, + actions.ui.get('spaces', 'manage'), + actions.ui.get('management', 'kibana', 'spaces'), + actions.ui.get('catalogue', 'spaces'), + ] + : []), + ...(expectEnterpriseSearch ? [actions.ui.get('enterpriseSearch', 'all')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'save')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []), + ]); + expect(actual).toHaveProperty(`${group}.read`, [ + actions.login, + ...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []), + ...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []), + ]); + }); }); } ); diff --git a/x-pack/plugins/security/server/authorization/privileges/privileges.ts b/x-pack/plugins/security/server/authorization/privileges/privileges.ts index e9e8ccbfe8d92..ee1901520df85 100644 --- a/x-pack/plugins/security/server/authorization/privileges/privileges.ts +++ b/x-pack/plugins/security/server/authorization/privileges/privileges.ts @@ -7,6 +7,10 @@ import { uniq } from 'lodash'; +import type { + FeatureKibanaPrivileges, + FeatureKibanaPrivilegesReference, +} from '@kbn/features-plugin/common'; import type { PluginSetupContract as FeaturesPluginSetup, KibanaFeature, @@ -41,6 +45,10 @@ export function privilegesFactory( const readActionsSet = new Set(); basePrivilegeFeatures.forEach((feature) => { + if (feature.hidden) { + return; + } + for (const { privilegeId, privilege } of featuresService.featurePrivilegeIterator(feature, { augmentWithSubFeaturePrivileges: true, licenseHasAtLeast, @@ -56,9 +64,31 @@ export function privilegesFactory( } }); - const allActions = [...allActionsSet]; - const readActions = [...readActionsSet]; + // Remember privilege as composable to update it later, once actions for all referenced privileges are also + // calculated and registered. + const composableFeaturePrivileges: Array<{ + featureId: string; + privilegeId: string; + excludeFromBasePrivileges?: boolean; + composedOf: readonly FeatureKibanaPrivilegesReference[]; + }> = []; + const tryStoreComposableFeature = ( + feature: KibanaFeature, + privilegeId: string, + privilege: FeatureKibanaPrivileges + ) => { + if (privilege.composedOf) { + composableFeaturePrivileges.push({ + featureId: feature.id, + privilegeId, + composedOf: privilege.composedOf, + excludeFromBasePrivileges: + feature.excludeFromBasePrivileges || privilege.excludeFromBasePrivileges, + }); + } + }; + const hiddenFeatures = new Set(); const featurePrivileges: Record> = {}; for (const feature of features) { featurePrivileges[feature.id] = {}; @@ -66,20 +96,26 @@ export function privilegesFactory( augmentWithSubFeaturePrivileges: true, licenseHasAtLeast, })) { - featurePrivileges[feature.id][featurePrivilege.privilegeId] = [ + const fullPrivilegeId = featurePrivilege.privilegeId; + featurePrivileges[feature.id][fullPrivilegeId] = [ actions.login, ...uniq(featurePrivilegeBuilder.getActions(featurePrivilege.privilege, feature)), ]; + + tryStoreComposableFeature(feature, fullPrivilegeId, featurePrivilege.privilege); } for (const featurePrivilege of featuresService.featurePrivilegeIterator(feature, { augmentWithSubFeaturePrivileges: false, licenseHasAtLeast, })) { - featurePrivileges[feature.id][`minimal_${featurePrivilege.privilegeId}`] = [ + const minimalPrivilegeId = `minimal_${featurePrivilege.privilegeId}`; + featurePrivileges[feature.id][minimalPrivilegeId] = [ actions.login, ...uniq(featurePrivilegeBuilder.getActions(featurePrivilege.privilege, feature)), ]; + + tryStoreComposableFeature(feature, minimalPrivilegeId, featurePrivilege.privilege); } if ( @@ -97,10 +133,53 @@ export function privilegesFactory( } } - if (Object.keys(featurePrivileges[feature.id]).length === 0) { - delete featurePrivileges[feature.id]; + if (feature.hidden || Object.keys(featurePrivileges[feature.id]).length === 0) { + hiddenFeatures.add(feature.id); } } + + // Update composable feature privileges to include and deduplicate actions from the referenced privileges. + // Note that we should do it _before_ removing hidden features. Also, currently, feature privilege composition + // doesn't respect the minimum license level required by the feature whose privileges are being included in + // another feature. This could potentially enable functionality in a license lower than originally intended. It + // might or might not be desired, but we're accepting this for now, as every attempt to compose a feature + // undergoes a stringent review process. + for (const composableFeature of composableFeaturePrivileges) { + const composedActions = composableFeature.composedOf.flatMap((privilegeReference) => + privilegeReference.privileges.flatMap( + (privilege) => featurePrivileges[privilegeReference.feature][privilege] + ) + ); + featurePrivileges[composableFeature.featureId][composableFeature.privilegeId] = [ + ...new Set( + featurePrivileges[composableFeature.featureId][composableFeature.privilegeId].concat( + composedActions + ) + ), + ]; + + if (!composableFeature.excludeFromBasePrivileges) { + for (const action of composedActions) { + // Login action is special since it's added explicitly for feature and base privileges. + if (action === actions.login) { + continue; + } + + allActionsSet.add(action); + if (composableFeature.privilegeId === 'read') { + readActionsSet.add(action); + } + } + } + } + + // Remove hidden features to avoid registering standalone privileges for them. + for (const hiddenFeatureId of hiddenFeatures) { + delete featurePrivileges[hiddenFeatureId]; + } + + const allActions = [...allActionsSet]; + const readActions = [...readActionsSet]; return { features: featurePrivileges, global: { diff --git a/x-pack/plugins/security/server/lib/role_utils.test.ts b/x-pack/plugins/security/server/lib/role_utils.test.ts index ec808f231808d..ebd083b8ff60e 100644 --- a/x-pack/plugins/security/server/lib/role_utils.test.ts +++ b/x-pack/plugins/security/server/lib/role_utils.test.ts @@ -5,7 +5,13 @@ * 2.0. */ -import { transformPrivilegesToElasticsearchPrivileges } from './role_utils'; +import { KibanaFeature } from '@kbn/features-plugin/common'; +import { getKibanaRoleSchema } from '@kbn/security-plugin-types-server'; + +import { + transformPrivilegesToElasticsearchPrivileges, + validateKibanaPrivileges, +} from './role_utils'; import { ALL_SPACES_ID } from '../../common/constants'; describe('transformPrivilegesToElasticsearchPrivileges', () => { @@ -24,3 +30,163 @@ describe('transformPrivilegesToElasticsearchPrivileges', () => { ]); }); }); + +describe('validateKibanaPrivileges', () => { + test('properly validates sub-feature privileges', () => { + const existingKibanaFeatures = [ + new KibanaFeature({ + id: 'feature1', + name: 'Feature1', + app: ['app1'], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: { + app: ['foo'], + catalogue: ['foo'], + savedObject: { all: ['foo'], read: [] }, + ui: ['save', 'show'], + }, + read: { + app: ['foo'], + catalogue: ['foo'], + savedObject: { all: [], read: ['foo'] }, + ui: ['show'], + }, + }, + }), + new KibanaFeature({ + id: 'feature2', + name: 'Feature2', + app: ['app2'], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: { + app: ['foo'], + catalogue: ['foo'], + savedObject: { all: ['foo'], read: [] }, + ui: ['save', 'show'], + }, + read: { + app: ['foo'], + catalogue: ['foo'], + savedObject: { all: [], read: ['foo'] }, + ui: ['show'], + }, + }, + subFeatures: [ + { + name: 'subFeature1', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'subFeaturePrivilege1', + name: 'SubFeaturePrivilege1', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: [], + }, + { + disabled: true, + id: 'subFeaturePrivilege2', + name: 'SubFeaturePrivilege2', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: [], + }, + { + disabled: true, + id: 'subFeaturePrivilege3', + name: 'SubFeaturePrivilege3', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: [], + }, + ], + }, + ], + }, + { + name: 'subFeature2', + privilegeGroups: [ + { + groupType: 'mutually_exclusive', + privileges: [ + { + disabled: true, + id: 'subFeaturePrivilege4', + name: 'SubFeaturePrivilege4', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: [], + }, + { + id: 'subFeaturePrivilege5', + name: 'SubFeaturePrivilege5', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: [], + }, + ], + }, + ], + }, + ], + }), + ]; + + const { validationErrors: emptyErrors } = validateKibanaPrivileges( + existingKibanaFeatures, + getKibanaRoleSchema(() => ({ global: [], space: [] })).validate([ + { + feature: { + feature2: ['all', 'subFeaturePrivilege1', 'subFeaturePrivilege5'], + }, + }, + ]) + ); + expect(emptyErrors).toHaveLength(0); + + const { validationErrors: nonEmptyErrors1 } = validateKibanaPrivileges( + existingKibanaFeatures, + getKibanaRoleSchema(() => ({ global: [], space: [] })).validate([ + { + feature: { + feature2: [ + 'all', + 'subFeaturePrivilege1', + 'subFeaturePrivilege2', + 'subFeaturePrivilege5', + ], + }, + }, + ]) + ); + expect(nonEmptyErrors1).toEqual([ + 'Feature [feature2] does not support specified sub-feature privileges [subFeaturePrivilege2].', + ]); + + const { validationErrors: nonEmptyErrors2 } = validateKibanaPrivileges( + existingKibanaFeatures, + getKibanaRoleSchema(() => ({ global: [], space: [] })).validate([ + { + feature: { + feature2: [ + 'all', + 'subFeaturePrivilege1', + 'subFeaturePrivilege2', + 'subFeaturePrivilege3', + 'subFeaturePrivilege4', + 'subFeaturePrivilege5', + ], + }, + }, + ]) + ); + expect(nonEmptyErrors2).toEqual([ + 'Feature [feature2] does not support specified sub-feature privileges [subFeaturePrivilege2, subFeaturePrivilege3].', + 'Feature [feature2] does not support specified sub-feature privileges [subFeaturePrivilege4].', + ]); + }); +}); diff --git a/x-pack/plugins/security/server/lib/role_utils.ts b/x-pack/plugins/security/server/lib/role_utils.ts index 1df5254a38df0..5e714cb1f7623 100644 --- a/x-pack/plugins/security/server/lib/role_utils.ts +++ b/x-pack/plugins/security/server/lib/role_utils.ts @@ -69,12 +69,12 @@ export const validateKibanaPrivileges = ( const validationErrors = kibanaPrivileges.flatMap((priv) => { const forAllSpaces = priv.spaces.includes(ALL_SPACES_ID); - return Object.entries(priv.feature ?? {}).flatMap(([featureId, feature]) => { + return Object.entries(priv.feature ?? {}).flatMap(([featureId, featurePrivileges]) => { const errors: string[] = []; - const kibanaFeature = kibanaFeatures.find((f) => f.id === featureId); + const kibanaFeature = kibanaFeatures.find((f) => f.id === featureId && !f.hidden); if (!kibanaFeature) return errors; - if (feature.includes('all')) { + if (featurePrivileges.includes('all')) { if (kibanaFeature.privileges?.all.disabled) { errors.push(`Feature [${featureId}] does not support privilege [all].`); } @@ -88,7 +88,7 @@ export const validateKibanaPrivileges = ( } } - if (feature.includes('read')) { + if (featurePrivileges.includes('read')) { if (kibanaFeature.privileges?.read.disabled) { errors.push(`Feature [${featureId}] does not support privilege [read].`); } @@ -103,12 +103,25 @@ export const validateKibanaPrivileges = ( } kibanaFeature.subFeatures.forEach((subFeature) => { - if ( + // Check if the definition includes any sub-feature privileges. + const subFeaturePrivileges = subFeature.privilegeGroups.flatMap((group) => + group.privileges.filter((privilege) => featurePrivileges.includes(privilege.id)) + ); + + // If the definition includes any disabled sub-feature privileges, return an error. + const disabledSubFeaturePrivileges = subFeaturePrivileges.filter( + (privilege) => privilege.disabled + ); + if (disabledSubFeaturePrivileges.length > 0) { + errors.push( + `Feature [${featureId}] does not support specified sub-feature privileges [${disabledSubFeaturePrivileges + .map((privilege) => privilege.id) + .join(', ')}].` + ); + } else if ( subFeature.requireAllSpaces && !forAllSpaces && - subFeature.privilegeGroups.some((group) => - group.privileges.some((privilege) => feature.includes(privilege.id)) - ) + subFeaturePrivileges.length > 0 ) { errors.push( `Sub-feature privilege [${kibanaFeature.name} - ${ diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts index 76d6580e8bbb8..d6ec69803b8f5 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts @@ -6,11 +6,25 @@ */ import expect from 'expect'; +import { KibanaFeatureConfig, SubFeaturePrivilegeConfig } from '@kbn/features-plugin/common'; import { FtrProviderContext } from '../../../ftr_provider_context'; +function collectSubFeaturesPrivileges(feature: KibanaFeatureConfig) { + return new Map( + feature.subFeatures?.flatMap((subFeature) => + subFeature.privilegeGroups.flatMap(({ privileges }) => + privileges.map( + (privilege) => [privilege.id, privilege] as [string, SubFeaturePrivilegeConfig] + ) + ) + ) ?? [] + ); +} + export default function ({ getService }: FtrProviderContext) { const svlCommonApi = getService('svlCommonApi'); const supertest = getService('supertest'); + const log = getService('log'); describe('security/authorization', function () { describe('route access', () => { @@ -76,5 +90,39 @@ export default function ({ getService }: FtrProviderContext) { }); }); }); + + describe('available features', () => { + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + let adminCredentials: { Cookie: string }; + + before(async () => { + // get auth header for Viewer role + adminCredentials = await svlUserManager.getApiCredentialsForRole('admin'); + }); + + it('all Dashboard and Discover sub-feature privileges are disabled', async () => { + const { body } = await supertestWithoutAuth + .get('/api/features') + .set(svlCommonApi.getInternalRequestHeader()) + .set(adminCredentials) + .expect(200); + + // We should make sure that neither Discover nor Dashboard displays any sub-feature privileges in Serverless. + // If any of these features adds a new sub-feature privilege we should make an explicit decision whether it + // should be displayed in Serverless. + const features = body as KibanaFeatureConfig[]; + for (const featureId of ['discover', 'dashboard']) { + const feature = features.find((f) => f.id === featureId)!; + const subFeaturesPrivileges = collectSubFeaturesPrivileges(feature); + for (const privilege of subFeaturesPrivileges.values()) { + log.debug( + `Verifying that ${privilege.id} sub-feature privilege of ${featureId} feature is disabled.` + ); + expect(privilege.disabled).toBe(true); + } + } + }); + }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts index c6257df072d85..dfd398fc360d0 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/index.feature_flags.ts @@ -11,6 +11,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Serverless observability API - feature flags', function () { loadTestFile(require.resolve('./custom_threshold_rule')); loadTestFile(require.resolve('./infra')); + loadTestFile(require.resolve('./platform_security')); loadTestFile(require.resolve('../common/platform_security/roles_routes_feature_flag.ts')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/authorization.ts new file mode 100644 index 0000000000000..25bdff734e379 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/authorization.ts @@ -0,0 +1,9585 @@ +/* + * 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 { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const svlCommonApi = getService('svlCommonApi'); + + describe('security/authorization', function () { + describe('available features', () => { + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + let adminCredentials: { Cookie: string }; + + before(async () => { + // get auth header for Viewer role + adminCredentials = await svlUserManager.getApiCredentialsForRole('admin'); + }); + + it('composite features', async () => { + const { body } = await supertestWithoutAuth + .get('/api/security/privileges?includeActions=true') + .set(svlCommonApi.getInternalRequestHeader()) + .set(adminCredentials) + .expect(200); + + // The following features are composed of other features in a way that is + // specific to the observability solution. + const compositeFeatureIds = [ + 'apm', + 'dashboard', + 'discover', + 'fleetv2', + 'infrastructure', + 'reporting', + 'slo', + 'uptime', + ]; + + const features = Object.fromEntries( + Object.entries(body.features).filter(([key]) => compositeFeatureIds.includes(key)) + ); + expectSnapshot(features).toMatchInline(` + Object { + "apm": Object { + "all": Array [ + "login:", + "api:apm", + "api:apm_write", + "api:rac", + "app:apm", + "app:ux", + "app:kibana", + "ui:catalogue/apm", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/apm", + "ui:navLinks/ux", + "ui:navLinks/kibana", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:apm-indices/bulk_get", + "saved_object:apm-indices/get", + "saved_object:apm-indices/find", + "saved_object:apm-indices/open_point_in_time", + "saved_object:apm-indices/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:apm/show", + "ui:apm/save", + "ui:apm/alerting:show", + "ui:apm/alerting:save", + "alerting:apm.error_rate/apm/rule/get", + "alerting:apm.error_rate/apm/rule/getRuleState", + "alerting:apm.error_rate/apm/rule/getAlertSummary", + "alerting:apm.error_rate/apm/rule/getExecutionLog", + "alerting:apm.error_rate/apm/rule/getActionErrorLog", + "alerting:apm.error_rate/apm/rule/find", + "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/apm/rule/getBackfill", + "alerting:apm.error_rate/apm/rule/findBackfill", + "alerting:apm.error_rate/apm/rule/create", + "alerting:apm.error_rate/apm/rule/delete", + "alerting:apm.error_rate/apm/rule/update", + "alerting:apm.error_rate/apm/rule/updateApiKey", + "alerting:apm.error_rate/apm/rule/enable", + "alerting:apm.error_rate/apm/rule/disable", + "alerting:apm.error_rate/apm/rule/muteAll", + "alerting:apm.error_rate/apm/rule/unmuteAll", + "alerting:apm.error_rate/apm/rule/muteAlert", + "alerting:apm.error_rate/apm/rule/unmuteAlert", + "alerting:apm.error_rate/apm/rule/snooze", + "alerting:apm.error_rate/apm/rule/bulkEdit", + "alerting:apm.error_rate/apm/rule/bulkDelete", + "alerting:apm.error_rate/apm/rule/bulkEnable", + "alerting:apm.error_rate/apm/rule/bulkDisable", + "alerting:apm.error_rate/apm/rule/unsnooze", + "alerting:apm.error_rate/apm/rule/runSoon", + "alerting:apm.error_rate/apm/rule/scheduleBackfill", + "alerting:apm.error_rate/apm/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/apm/rule/get", + "alerting:apm.transaction_error_rate/apm/rule/getRuleState", + "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/apm/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/apm/rule/find", + "alerting:apm.transaction_error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/apm/rule/getBackfill", + "alerting:apm.transaction_error_rate/apm/rule/findBackfill", + "alerting:apm.transaction_error_rate/apm/rule/create", + "alerting:apm.transaction_error_rate/apm/rule/delete", + "alerting:apm.transaction_error_rate/apm/rule/update", + "alerting:apm.transaction_error_rate/apm/rule/updateApiKey", + "alerting:apm.transaction_error_rate/apm/rule/enable", + "alerting:apm.transaction_error_rate/apm/rule/disable", + "alerting:apm.transaction_error_rate/apm/rule/muteAll", + "alerting:apm.transaction_error_rate/apm/rule/unmuteAll", + "alerting:apm.transaction_error_rate/apm/rule/muteAlert", + "alerting:apm.transaction_error_rate/apm/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/apm/rule/snooze", + "alerting:apm.transaction_error_rate/apm/rule/bulkEdit", + "alerting:apm.transaction_error_rate/apm/rule/bulkDelete", + "alerting:apm.transaction_error_rate/apm/rule/bulkEnable", + "alerting:apm.transaction_error_rate/apm/rule/bulkDisable", + "alerting:apm.transaction_error_rate/apm/rule/unsnooze", + "alerting:apm.transaction_error_rate/apm/rule/runSoon", + "alerting:apm.transaction_error_rate/apm/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/apm/rule/deleteBackfill", + "alerting:apm.transaction_duration/apm/rule/get", + "alerting:apm.transaction_duration/apm/rule/getRuleState", + "alerting:apm.transaction_duration/apm/rule/getAlertSummary", + "alerting:apm.transaction_duration/apm/rule/getExecutionLog", + "alerting:apm.transaction_duration/apm/rule/getActionErrorLog", + "alerting:apm.transaction_duration/apm/rule/find", + "alerting:apm.transaction_duration/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/apm/rule/getBackfill", + "alerting:apm.transaction_duration/apm/rule/findBackfill", + "alerting:apm.transaction_duration/apm/rule/create", + "alerting:apm.transaction_duration/apm/rule/delete", + "alerting:apm.transaction_duration/apm/rule/update", + "alerting:apm.transaction_duration/apm/rule/updateApiKey", + "alerting:apm.transaction_duration/apm/rule/enable", + "alerting:apm.transaction_duration/apm/rule/disable", + "alerting:apm.transaction_duration/apm/rule/muteAll", + "alerting:apm.transaction_duration/apm/rule/unmuteAll", + "alerting:apm.transaction_duration/apm/rule/muteAlert", + "alerting:apm.transaction_duration/apm/rule/unmuteAlert", + "alerting:apm.transaction_duration/apm/rule/snooze", + "alerting:apm.transaction_duration/apm/rule/bulkEdit", + "alerting:apm.transaction_duration/apm/rule/bulkDelete", + "alerting:apm.transaction_duration/apm/rule/bulkEnable", + "alerting:apm.transaction_duration/apm/rule/bulkDisable", + "alerting:apm.transaction_duration/apm/rule/unsnooze", + "alerting:apm.transaction_duration/apm/rule/runSoon", + "alerting:apm.transaction_duration/apm/rule/scheduleBackfill", + "alerting:apm.transaction_duration/apm/rule/deleteBackfill", + "alerting:apm.anomaly/apm/rule/get", + "alerting:apm.anomaly/apm/rule/getRuleState", + "alerting:apm.anomaly/apm/rule/getAlertSummary", + "alerting:apm.anomaly/apm/rule/getExecutionLog", + "alerting:apm.anomaly/apm/rule/getActionErrorLog", + "alerting:apm.anomaly/apm/rule/find", + "alerting:apm.anomaly/apm/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/apm/rule/getBackfill", + "alerting:apm.anomaly/apm/rule/findBackfill", + "alerting:apm.anomaly/apm/rule/create", + "alerting:apm.anomaly/apm/rule/delete", + "alerting:apm.anomaly/apm/rule/update", + "alerting:apm.anomaly/apm/rule/updateApiKey", + "alerting:apm.anomaly/apm/rule/enable", + "alerting:apm.anomaly/apm/rule/disable", + "alerting:apm.anomaly/apm/rule/muteAll", + "alerting:apm.anomaly/apm/rule/unmuteAll", + "alerting:apm.anomaly/apm/rule/muteAlert", + "alerting:apm.anomaly/apm/rule/unmuteAlert", + "alerting:apm.anomaly/apm/rule/snooze", + "alerting:apm.anomaly/apm/rule/bulkEdit", + "alerting:apm.anomaly/apm/rule/bulkDelete", + "alerting:apm.anomaly/apm/rule/bulkEnable", + "alerting:apm.anomaly/apm/rule/bulkDisable", + "alerting:apm.anomaly/apm/rule/unsnooze", + "alerting:apm.anomaly/apm/rule/runSoon", + "alerting:apm.anomaly/apm/rule/scheduleBackfill", + "alerting:apm.anomaly/apm/rule/deleteBackfill", + "alerting:apm.error_rate/apm/alert/get", + "alerting:apm.error_rate/apm/alert/find", + "alerting:apm.error_rate/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/apm/alert/getAlertSummary", + "alerting:apm.error_rate/apm/alert/update", + "alerting:apm.transaction_error_rate/apm/alert/get", + "alerting:apm.transaction_error_rate/apm/alert/find", + "alerting:apm.transaction_error_rate/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/apm/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/alert/update", + "alerting:apm.transaction_duration/apm/alert/get", + "alerting:apm.transaction_duration/apm/alert/find", + "alerting:apm.transaction_duration/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/apm/alert/getAlertSummary", + "alerting:apm.transaction_duration/apm/alert/update", + "alerting:apm.anomaly/apm/alert/get", + "alerting:apm.anomaly/apm/alert/find", + "alerting:apm.anomaly/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/apm/alert/getAlertSummary", + "alerting:apm.anomaly/apm/alert/update", + "api:infra", + "app:infra", + "app:logs", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:navLinks/infra", + "ui:navLinks/logs", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-ui-source/create", + "saved_object:infrastructure-ui-source/bulk_create", + "saved_object:infrastructure-ui-source/update", + "saved_object:infrastructure-ui-source/bulk_update", + "saved_object:infrastructure-ui-source/delete", + "saved_object:infrastructure-ui-source/bulk_delete", + "saved_object:infrastructure-ui-source/share_to_space", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/create", + "saved_object:infrastructure-monitoring-log-view/bulk_create", + "saved_object:infrastructure-monitoring-log-view/update", + "saved_object:infrastructure-monitoring-log-view/bulk_update", + "saved_object:infrastructure-monitoring-log-view/delete", + "saved_object:infrastructure-monitoring-log-view/bulk_delete", + "saved_object:infrastructure-monitoring-log-view/share_to_space", + "ui:logs/show", + "ui:logs/configureSource", + "ui:logs/save", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/rule/create", + "alerting:logs.alert.document.count/logs/rule/delete", + "alerting:logs.alert.document.count/logs/rule/update", + "alerting:logs.alert.document.count/logs/rule/updateApiKey", + "alerting:logs.alert.document.count/logs/rule/enable", + "alerting:logs.alert.document.count/logs/rule/disable", + "alerting:logs.alert.document.count/logs/rule/muteAll", + "alerting:logs.alert.document.count/logs/rule/unmuteAll", + "alerting:logs.alert.document.count/logs/rule/muteAlert", + "alerting:logs.alert.document.count/logs/rule/unmuteAlert", + "alerting:logs.alert.document.count/logs/rule/snooze", + "alerting:logs.alert.document.count/logs/rule/bulkEdit", + "alerting:logs.alert.document.count/logs/rule/bulkDelete", + "alerting:logs.alert.document.count/logs/rule/bulkEnable", + "alerting:logs.alert.document.count/logs/rule/bulkDisable", + "alerting:logs.alert.document.count/logs/rule/unsnooze", + "alerting:logs.alert.document.count/logs/rule/runSoon", + "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", + "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/create", + "alerting:.es-query/logs/rule/delete", + "alerting:.es-query/logs/rule/update", + "alerting:.es-query/logs/rule/updateApiKey", + "alerting:.es-query/logs/rule/enable", + "alerting:.es-query/logs/rule/disable", + "alerting:.es-query/logs/rule/muteAll", + "alerting:.es-query/logs/rule/unmuteAll", + "alerting:.es-query/logs/rule/muteAlert", + "alerting:.es-query/logs/rule/unmuteAlert", + "alerting:.es-query/logs/rule/snooze", + "alerting:.es-query/logs/rule/bulkEdit", + "alerting:.es-query/logs/rule/bulkDelete", + "alerting:.es-query/logs/rule/bulkEnable", + "alerting:.es-query/logs/rule/bulkDisable", + "alerting:.es-query/logs/rule/unsnooze", + "alerting:.es-query/logs/rule/runSoon", + "alerting:.es-query/logs/rule/scheduleBackfill", + "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/create", + "alerting:observability.rules.custom_threshold/logs/rule/delete", + "alerting:observability.rules.custom_threshold/logs/rule/update", + "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/logs/rule/enable", + "alerting:observability.rules.custom_threshold/logs/rule/disable", + "alerting:observability.rules.custom_threshold/logs/rule/muteAll", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/snooze", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", + "alerting:observability.rules.custom_threshold/logs/rule/runSoon", + "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/logs/alert/update", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/update", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "minimal_all": Array [ + "login:", + "api:apm", + "api:apm_write", + "api:rac", + "app:apm", + "app:ux", + "app:kibana", + "ui:catalogue/apm", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/apm", + "ui:navLinks/ux", + "ui:navLinks/kibana", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:apm-indices/bulk_get", + "saved_object:apm-indices/get", + "saved_object:apm-indices/find", + "saved_object:apm-indices/open_point_in_time", + "saved_object:apm-indices/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:apm/show", + "ui:apm/save", + "ui:apm/alerting:show", + "ui:apm/alerting:save", + "alerting:apm.error_rate/apm/rule/get", + "alerting:apm.error_rate/apm/rule/getRuleState", + "alerting:apm.error_rate/apm/rule/getAlertSummary", + "alerting:apm.error_rate/apm/rule/getExecutionLog", + "alerting:apm.error_rate/apm/rule/getActionErrorLog", + "alerting:apm.error_rate/apm/rule/find", + "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/apm/rule/getBackfill", + "alerting:apm.error_rate/apm/rule/findBackfill", + "alerting:apm.error_rate/apm/rule/create", + "alerting:apm.error_rate/apm/rule/delete", + "alerting:apm.error_rate/apm/rule/update", + "alerting:apm.error_rate/apm/rule/updateApiKey", + "alerting:apm.error_rate/apm/rule/enable", + "alerting:apm.error_rate/apm/rule/disable", + "alerting:apm.error_rate/apm/rule/muteAll", + "alerting:apm.error_rate/apm/rule/unmuteAll", + "alerting:apm.error_rate/apm/rule/muteAlert", + "alerting:apm.error_rate/apm/rule/unmuteAlert", + "alerting:apm.error_rate/apm/rule/snooze", + "alerting:apm.error_rate/apm/rule/bulkEdit", + "alerting:apm.error_rate/apm/rule/bulkDelete", + "alerting:apm.error_rate/apm/rule/bulkEnable", + "alerting:apm.error_rate/apm/rule/bulkDisable", + "alerting:apm.error_rate/apm/rule/unsnooze", + "alerting:apm.error_rate/apm/rule/runSoon", + "alerting:apm.error_rate/apm/rule/scheduleBackfill", + "alerting:apm.error_rate/apm/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/apm/rule/get", + "alerting:apm.transaction_error_rate/apm/rule/getRuleState", + "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/apm/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/apm/rule/find", + "alerting:apm.transaction_error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/apm/rule/getBackfill", + "alerting:apm.transaction_error_rate/apm/rule/findBackfill", + "alerting:apm.transaction_error_rate/apm/rule/create", + "alerting:apm.transaction_error_rate/apm/rule/delete", + "alerting:apm.transaction_error_rate/apm/rule/update", + "alerting:apm.transaction_error_rate/apm/rule/updateApiKey", + "alerting:apm.transaction_error_rate/apm/rule/enable", + "alerting:apm.transaction_error_rate/apm/rule/disable", + "alerting:apm.transaction_error_rate/apm/rule/muteAll", + "alerting:apm.transaction_error_rate/apm/rule/unmuteAll", + "alerting:apm.transaction_error_rate/apm/rule/muteAlert", + "alerting:apm.transaction_error_rate/apm/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/apm/rule/snooze", + "alerting:apm.transaction_error_rate/apm/rule/bulkEdit", + "alerting:apm.transaction_error_rate/apm/rule/bulkDelete", + "alerting:apm.transaction_error_rate/apm/rule/bulkEnable", + "alerting:apm.transaction_error_rate/apm/rule/bulkDisable", + "alerting:apm.transaction_error_rate/apm/rule/unsnooze", + "alerting:apm.transaction_error_rate/apm/rule/runSoon", + "alerting:apm.transaction_error_rate/apm/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/apm/rule/deleteBackfill", + "alerting:apm.transaction_duration/apm/rule/get", + "alerting:apm.transaction_duration/apm/rule/getRuleState", + "alerting:apm.transaction_duration/apm/rule/getAlertSummary", + "alerting:apm.transaction_duration/apm/rule/getExecutionLog", + "alerting:apm.transaction_duration/apm/rule/getActionErrorLog", + "alerting:apm.transaction_duration/apm/rule/find", + "alerting:apm.transaction_duration/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/apm/rule/getBackfill", + "alerting:apm.transaction_duration/apm/rule/findBackfill", + "alerting:apm.transaction_duration/apm/rule/create", + "alerting:apm.transaction_duration/apm/rule/delete", + "alerting:apm.transaction_duration/apm/rule/update", + "alerting:apm.transaction_duration/apm/rule/updateApiKey", + "alerting:apm.transaction_duration/apm/rule/enable", + "alerting:apm.transaction_duration/apm/rule/disable", + "alerting:apm.transaction_duration/apm/rule/muteAll", + "alerting:apm.transaction_duration/apm/rule/unmuteAll", + "alerting:apm.transaction_duration/apm/rule/muteAlert", + "alerting:apm.transaction_duration/apm/rule/unmuteAlert", + "alerting:apm.transaction_duration/apm/rule/snooze", + "alerting:apm.transaction_duration/apm/rule/bulkEdit", + "alerting:apm.transaction_duration/apm/rule/bulkDelete", + "alerting:apm.transaction_duration/apm/rule/bulkEnable", + "alerting:apm.transaction_duration/apm/rule/bulkDisable", + "alerting:apm.transaction_duration/apm/rule/unsnooze", + "alerting:apm.transaction_duration/apm/rule/runSoon", + "alerting:apm.transaction_duration/apm/rule/scheduleBackfill", + "alerting:apm.transaction_duration/apm/rule/deleteBackfill", + "alerting:apm.anomaly/apm/rule/get", + "alerting:apm.anomaly/apm/rule/getRuleState", + "alerting:apm.anomaly/apm/rule/getAlertSummary", + "alerting:apm.anomaly/apm/rule/getExecutionLog", + "alerting:apm.anomaly/apm/rule/getActionErrorLog", + "alerting:apm.anomaly/apm/rule/find", + "alerting:apm.anomaly/apm/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/apm/rule/getBackfill", + "alerting:apm.anomaly/apm/rule/findBackfill", + "alerting:apm.anomaly/apm/rule/create", + "alerting:apm.anomaly/apm/rule/delete", + "alerting:apm.anomaly/apm/rule/update", + "alerting:apm.anomaly/apm/rule/updateApiKey", + "alerting:apm.anomaly/apm/rule/enable", + "alerting:apm.anomaly/apm/rule/disable", + "alerting:apm.anomaly/apm/rule/muteAll", + "alerting:apm.anomaly/apm/rule/unmuteAll", + "alerting:apm.anomaly/apm/rule/muteAlert", + "alerting:apm.anomaly/apm/rule/unmuteAlert", + "alerting:apm.anomaly/apm/rule/snooze", + "alerting:apm.anomaly/apm/rule/bulkEdit", + "alerting:apm.anomaly/apm/rule/bulkDelete", + "alerting:apm.anomaly/apm/rule/bulkEnable", + "alerting:apm.anomaly/apm/rule/bulkDisable", + "alerting:apm.anomaly/apm/rule/unsnooze", + "alerting:apm.anomaly/apm/rule/runSoon", + "alerting:apm.anomaly/apm/rule/scheduleBackfill", + "alerting:apm.anomaly/apm/rule/deleteBackfill", + "alerting:apm.error_rate/apm/alert/get", + "alerting:apm.error_rate/apm/alert/find", + "alerting:apm.error_rate/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/apm/alert/getAlertSummary", + "alerting:apm.error_rate/apm/alert/update", + "alerting:apm.transaction_error_rate/apm/alert/get", + "alerting:apm.transaction_error_rate/apm/alert/find", + "alerting:apm.transaction_error_rate/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/apm/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/alert/update", + "alerting:apm.transaction_duration/apm/alert/get", + "alerting:apm.transaction_duration/apm/alert/find", + "alerting:apm.transaction_duration/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/apm/alert/getAlertSummary", + "alerting:apm.transaction_duration/apm/alert/update", + "alerting:apm.anomaly/apm/alert/get", + "alerting:apm.anomaly/apm/alert/find", + "alerting:apm.anomaly/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/apm/alert/getAlertSummary", + "alerting:apm.anomaly/apm/alert/update", + "api:infra", + "app:infra", + "app:logs", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:navLinks/infra", + "ui:navLinks/logs", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-ui-source/create", + "saved_object:infrastructure-ui-source/bulk_create", + "saved_object:infrastructure-ui-source/update", + "saved_object:infrastructure-ui-source/bulk_update", + "saved_object:infrastructure-ui-source/delete", + "saved_object:infrastructure-ui-source/bulk_delete", + "saved_object:infrastructure-ui-source/share_to_space", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/create", + "saved_object:infrastructure-monitoring-log-view/bulk_create", + "saved_object:infrastructure-monitoring-log-view/update", + "saved_object:infrastructure-monitoring-log-view/bulk_update", + "saved_object:infrastructure-monitoring-log-view/delete", + "saved_object:infrastructure-monitoring-log-view/bulk_delete", + "saved_object:infrastructure-monitoring-log-view/share_to_space", + "ui:logs/show", + "ui:logs/configureSource", + "ui:logs/save", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/rule/create", + "alerting:logs.alert.document.count/logs/rule/delete", + "alerting:logs.alert.document.count/logs/rule/update", + "alerting:logs.alert.document.count/logs/rule/updateApiKey", + "alerting:logs.alert.document.count/logs/rule/enable", + "alerting:logs.alert.document.count/logs/rule/disable", + "alerting:logs.alert.document.count/logs/rule/muteAll", + "alerting:logs.alert.document.count/logs/rule/unmuteAll", + "alerting:logs.alert.document.count/logs/rule/muteAlert", + "alerting:logs.alert.document.count/logs/rule/unmuteAlert", + "alerting:logs.alert.document.count/logs/rule/snooze", + "alerting:logs.alert.document.count/logs/rule/bulkEdit", + "alerting:logs.alert.document.count/logs/rule/bulkDelete", + "alerting:logs.alert.document.count/logs/rule/bulkEnable", + "alerting:logs.alert.document.count/logs/rule/bulkDisable", + "alerting:logs.alert.document.count/logs/rule/unsnooze", + "alerting:logs.alert.document.count/logs/rule/runSoon", + "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", + "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/create", + "alerting:.es-query/logs/rule/delete", + "alerting:.es-query/logs/rule/update", + "alerting:.es-query/logs/rule/updateApiKey", + "alerting:.es-query/logs/rule/enable", + "alerting:.es-query/logs/rule/disable", + "alerting:.es-query/logs/rule/muteAll", + "alerting:.es-query/logs/rule/unmuteAll", + "alerting:.es-query/logs/rule/muteAlert", + "alerting:.es-query/logs/rule/unmuteAlert", + "alerting:.es-query/logs/rule/snooze", + "alerting:.es-query/logs/rule/bulkEdit", + "alerting:.es-query/logs/rule/bulkDelete", + "alerting:.es-query/logs/rule/bulkEnable", + "alerting:.es-query/logs/rule/bulkDisable", + "alerting:.es-query/logs/rule/unsnooze", + "alerting:.es-query/logs/rule/runSoon", + "alerting:.es-query/logs/rule/scheduleBackfill", + "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/create", + "alerting:observability.rules.custom_threshold/logs/rule/delete", + "alerting:observability.rules.custom_threshold/logs/rule/update", + "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/logs/rule/enable", + "alerting:observability.rules.custom_threshold/logs/rule/disable", + "alerting:observability.rules.custom_threshold/logs/rule/muteAll", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/snooze", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", + "alerting:observability.rules.custom_threshold/logs/rule/runSoon", + "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/logs/alert/update", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/update", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "minimal_read": Array [ + "login:", + "api:apm", + "api:rac", + "app:apm", + "app:ux", + "app:kibana", + "ui:catalogue/apm", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/apm", + "ui:navLinks/ux", + "ui:navLinks/kibana", + "saved_object:apm-indices/bulk_get", + "saved_object:apm-indices/get", + "saved_object:apm-indices/find", + "saved_object:apm-indices/open_point_in_time", + "saved_object:apm-indices/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:apm/show", + "ui:apm/alerting:show", + "alerting:apm.error_rate/apm/rule/get", + "alerting:apm.error_rate/apm/rule/getRuleState", + "alerting:apm.error_rate/apm/rule/getAlertSummary", + "alerting:apm.error_rate/apm/rule/getExecutionLog", + "alerting:apm.error_rate/apm/rule/getActionErrorLog", + "alerting:apm.error_rate/apm/rule/find", + "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/apm/rule/getBackfill", + "alerting:apm.error_rate/apm/rule/findBackfill", + "alerting:apm.transaction_error_rate/apm/rule/get", + "alerting:apm.transaction_error_rate/apm/rule/getRuleState", + "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/apm/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/apm/rule/find", + "alerting:apm.transaction_error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/apm/rule/getBackfill", + "alerting:apm.transaction_error_rate/apm/rule/findBackfill", + "alerting:apm.transaction_duration/apm/rule/get", + "alerting:apm.transaction_duration/apm/rule/getRuleState", + "alerting:apm.transaction_duration/apm/rule/getAlertSummary", + "alerting:apm.transaction_duration/apm/rule/getExecutionLog", + "alerting:apm.transaction_duration/apm/rule/getActionErrorLog", + "alerting:apm.transaction_duration/apm/rule/find", + "alerting:apm.transaction_duration/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/apm/rule/getBackfill", + "alerting:apm.transaction_duration/apm/rule/findBackfill", + "alerting:apm.anomaly/apm/rule/get", + "alerting:apm.anomaly/apm/rule/getRuleState", + "alerting:apm.anomaly/apm/rule/getAlertSummary", + "alerting:apm.anomaly/apm/rule/getExecutionLog", + "alerting:apm.anomaly/apm/rule/getActionErrorLog", + "alerting:apm.anomaly/apm/rule/find", + "alerting:apm.anomaly/apm/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/apm/rule/getBackfill", + "alerting:apm.anomaly/apm/rule/findBackfill", + "alerting:apm.error_rate/apm/alert/get", + "alerting:apm.error_rate/apm/alert/find", + "alerting:apm.error_rate/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/apm/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/alert/get", + "alerting:apm.transaction_error_rate/apm/alert/find", + "alerting:apm.transaction_error_rate/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/apm/alert/getAlertSummary", + "alerting:apm.transaction_duration/apm/alert/get", + "alerting:apm.transaction_duration/apm/alert/find", + "alerting:apm.transaction_duration/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/apm/alert/getAlertSummary", + "alerting:apm.anomaly/apm/alert/get", + "alerting:apm.anomaly/apm/alert/find", + "alerting:apm.anomaly/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/apm/alert/getAlertSummary", + "api:infra", + "app:infra", + "app:logs", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:navLinks/infra", + "ui:navLinks/logs", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "ui:logs/show", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + "read": Array [ + "login:", + "api:apm", + "api:rac", + "app:apm", + "app:ux", + "app:kibana", + "ui:catalogue/apm", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/apm", + "ui:navLinks/ux", + "ui:navLinks/kibana", + "saved_object:apm-indices/bulk_get", + "saved_object:apm-indices/get", + "saved_object:apm-indices/find", + "saved_object:apm-indices/open_point_in_time", + "saved_object:apm-indices/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:apm/show", + "ui:apm/alerting:show", + "alerting:apm.error_rate/apm/rule/get", + "alerting:apm.error_rate/apm/rule/getRuleState", + "alerting:apm.error_rate/apm/rule/getAlertSummary", + "alerting:apm.error_rate/apm/rule/getExecutionLog", + "alerting:apm.error_rate/apm/rule/getActionErrorLog", + "alerting:apm.error_rate/apm/rule/find", + "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/apm/rule/getBackfill", + "alerting:apm.error_rate/apm/rule/findBackfill", + "alerting:apm.transaction_error_rate/apm/rule/get", + "alerting:apm.transaction_error_rate/apm/rule/getRuleState", + "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/apm/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/apm/rule/find", + "alerting:apm.transaction_error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/apm/rule/getBackfill", + "alerting:apm.transaction_error_rate/apm/rule/findBackfill", + "alerting:apm.transaction_duration/apm/rule/get", + "alerting:apm.transaction_duration/apm/rule/getRuleState", + "alerting:apm.transaction_duration/apm/rule/getAlertSummary", + "alerting:apm.transaction_duration/apm/rule/getExecutionLog", + "alerting:apm.transaction_duration/apm/rule/getActionErrorLog", + "alerting:apm.transaction_duration/apm/rule/find", + "alerting:apm.transaction_duration/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/apm/rule/getBackfill", + "alerting:apm.transaction_duration/apm/rule/findBackfill", + "alerting:apm.anomaly/apm/rule/get", + "alerting:apm.anomaly/apm/rule/getRuleState", + "alerting:apm.anomaly/apm/rule/getAlertSummary", + "alerting:apm.anomaly/apm/rule/getExecutionLog", + "alerting:apm.anomaly/apm/rule/getActionErrorLog", + "alerting:apm.anomaly/apm/rule/find", + "alerting:apm.anomaly/apm/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/apm/rule/getBackfill", + "alerting:apm.anomaly/apm/rule/findBackfill", + "alerting:apm.error_rate/apm/alert/get", + "alerting:apm.error_rate/apm/alert/find", + "alerting:apm.error_rate/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/apm/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/alert/get", + "alerting:apm.transaction_error_rate/apm/alert/find", + "alerting:apm.transaction_error_rate/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/apm/alert/getAlertSummary", + "alerting:apm.transaction_duration/apm/alert/get", + "alerting:apm.transaction_duration/apm/alert/find", + "alerting:apm.transaction_duration/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/apm/alert/getAlertSummary", + "alerting:apm.anomaly/apm/alert/get", + "alerting:apm.anomaly/apm/alert/find", + "alerting:apm.anomaly/apm/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/apm/alert/getAlertSummary", + "api:infra", + "app:infra", + "app:logs", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:navLinks/infra", + "ui:navLinks/logs", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "ui:logs/show", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + }, + "dashboard": Object { + "all": Array [ + "login:", + "api:bulkGetUserProfiles", + "api:store_search_session", + "api:generateReport", + "api:downloadCsv", + "app:dashboards", + "app:kibana", + "ui:catalogue/dashboard", + "ui:management/kibana/search_sessions", + "ui:management/insightsAndAlerting/reporting", + "ui:navLinks/dashboards", + "ui:navLinks/kibana", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:dashboard/create", + "saved_object:dashboard/bulk_create", + "saved_object:dashboard/update", + "saved_object:dashboard/bulk_update", + "saved_object:dashboard/delete", + "saved_object:dashboard/bulk_delete", + "saved_object:dashboard/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "ui:dashboard/createNew", + "ui:dashboard/show", + "ui:dashboard/showWriteControls", + "ui:dashboard/saveQuery", + "ui:dashboard/createShortUrl", + "ui:dashboard/storeSearchSession", + "ui:dashboard/generateScreenshot", + "ui:dashboard/downloadCsv", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "saved_object:map/create", + "saved_object:map/bulk_create", + "saved_object:map/update", + "saved_object:map/bulk_update", + "saved_object:map/delete", + "saved_object:map/bulk_delete", + "saved_object:map/share_to_space", + "ui:maps/save", + "ui:maps/show", + "ui:maps/saveQuery", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "saved_object:visualization/create", + "saved_object:visualization/bulk_create", + "saved_object:visualization/update", + "saved_object:visualization/bulk_update", + "saved_object:visualization/delete", + "saved_object:visualization/bulk_delete", + "saved_object:visualization/share_to_space", + "saved_object:lens/create", + "saved_object:lens/bulk_create", + "saved_object:lens/update", + "saved_object:lens/bulk_update", + "saved_object:lens/delete", + "saved_object:lens/bulk_delete", + "saved_object:lens/share_to_space", + "ui:visualize/show", + "ui:visualize/delete", + "ui:visualize/save", + "ui:visualize/saveQuery", + "ui:visualize/createShortUrl", + "ui:visualize/generateScreenshot", + ], + "download_csv_report": Array [ + "login:", + "api:downloadCsv", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/downloadCsv", + ], + "generate_report": Array [ + "login:", + "api:generateReport", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/generateScreenshot", + ], + "minimal_all": Array [ + "login:", + "api:bulkGetUserProfiles", + "app:dashboards", + "app:kibana", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "ui:navLinks/kibana", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:dashboard/create", + "saved_object:dashboard/bulk_create", + "saved_object:dashboard/update", + "saved_object:dashboard/bulk_update", + "saved_object:dashboard/delete", + "saved_object:dashboard/bulk_delete", + "saved_object:dashboard/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:dashboard/createNew", + "ui:dashboard/show", + "ui:dashboard/showWriteControls", + "ui:dashboard/saveQuery", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "saved_object:map/create", + "saved_object:map/bulk_create", + "saved_object:map/update", + "saved_object:map/bulk_update", + "saved_object:map/delete", + "saved_object:map/bulk_delete", + "saved_object:map/share_to_space", + "ui:maps/save", + "ui:maps/show", + "ui:maps/saveQuery", + "api:generateReport", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:management/insightsAndAlerting/reporting", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "saved_object:visualization/create", + "saved_object:visualization/bulk_create", + "saved_object:visualization/update", + "saved_object:visualization/bulk_update", + "saved_object:visualization/delete", + "saved_object:visualization/bulk_delete", + "saved_object:visualization/share_to_space", + "saved_object:lens/create", + "saved_object:lens/bulk_create", + "saved_object:lens/update", + "saved_object:lens/bulk_update", + "saved_object:lens/delete", + "saved_object:lens/bulk_delete", + "saved_object:lens/share_to_space", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "ui:visualize/show", + "ui:visualize/delete", + "ui:visualize/save", + "ui:visualize/saveQuery", + "ui:visualize/createShortUrl", + "ui:visualize/generateScreenshot", + ], + "minimal_read": Array [ + "login:", + "api:bulkGetUserProfiles", + "app:dashboards", + "app:kibana", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "ui:navLinks/kibana", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:dashboard/show", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "ui:maps/show", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "ui:visualize/show", + "ui:visualize/createShortUrl", + ], + "read": Array [ + "login:", + "api:bulkGetUserProfiles", + "app:dashboards", + "app:kibana", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "ui:navLinks/kibana", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "ui:dashboard/show", + "ui:dashboard/createShortUrl", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "ui:maps/show", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "ui:visualize/show", + "ui:visualize/createShortUrl", + ], + "store_search_session": Array [ + "login:", + "api:store_search_session", + "ui:management/kibana/search_sessions", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "ui:dashboard/storeSearchSession", + ], + "url_create": Array [ + "login:", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "ui:dashboard/createShortUrl", + ], + }, + "discover": Object { + "all": Array [ + "login:", + "api:fileUpload:analyzeFile", + "api:store_search_session", + "api:generateReport", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:management/kibana/search_sessions", + "ui:management/insightsAndAlerting/reporting", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:search/create", + "saved_object:search/bulk_create", + "saved_object:search/update", + "saved_object:search/bulk_update", + "saved_object:search/delete", + "saved_object:search/bulk_delete", + "saved_object:search/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "ui:discover/show", + "ui:discover/save", + "ui:discover/saveQuery", + "ui:discover/createShortUrl", + "ui:discover/storeSearchSession", + "ui:discover/generateCsv", + "api:rac", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "generate_report": Array [ + "login:", + "api:generateReport", + "ui:management/insightsAndAlerting/reporting", + "ui:discover/generateCsv", + ], + "minimal_all": Array [ + "login:", + "api:fileUpload:analyzeFile", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:search/create", + "saved_object:search/bulk_create", + "saved_object:search/update", + "saved_object:search/bulk_update", + "saved_object:search/delete", + "saved_object:search/bulk_delete", + "saved_object:search/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:discover/show", + "ui:discover/save", + "ui:discover/saveQuery", + "api:rac", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "minimal_read": Array [ + "login:", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:discover/show", + "api:rac", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + "read": Array [ + "login:", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "ui:discover/show", + "ui:discover/createShortUrl", + "api:rac", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + "store_search_session": Array [ + "login:", + "api:store_search_session", + "ui:management/kibana/search_sessions", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "ui:discover/storeSearchSession", + ], + "url_create": Array [ + "login:", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "ui:discover/createShortUrl", + ], + }, + "fleetv2": Object { + "all": Array [ + "login:", + "api:fleet-read", + "api:fleet-all", + "app:fleet", + "ui:catalogue/fleet", + "ui:navLinks/fleet", + "saved_object:ingest-outputs/bulk_get", + "saved_object:ingest-outputs/get", + "saved_object:ingest-outputs/find", + "saved_object:ingest-outputs/open_point_in_time", + "saved_object:ingest-outputs/close_point_in_time", + "saved_object:ingest-outputs/create", + "saved_object:ingest-outputs/bulk_create", + "saved_object:ingest-outputs/update", + "saved_object:ingest-outputs/bulk_update", + "saved_object:ingest-outputs/delete", + "saved_object:ingest-outputs/bulk_delete", + "saved_object:ingest-outputs/share_to_space", + "saved_object:ingest-agent-policies/bulk_get", + "saved_object:ingest-agent-policies/get", + "saved_object:ingest-agent-policies/find", + "saved_object:ingest-agent-policies/open_point_in_time", + "saved_object:ingest-agent-policies/close_point_in_time", + "saved_object:ingest-agent-policies/create", + "saved_object:ingest-agent-policies/bulk_create", + "saved_object:ingest-agent-policies/update", + "saved_object:ingest-agent-policies/bulk_update", + "saved_object:ingest-agent-policies/delete", + "saved_object:ingest-agent-policies/bulk_delete", + "saved_object:ingest-agent-policies/share_to_space", + "saved_object:ingest-package-policies/bulk_get", + "saved_object:ingest-package-policies/get", + "saved_object:ingest-package-policies/find", + "saved_object:ingest-package-policies/open_point_in_time", + "saved_object:ingest-package-policies/close_point_in_time", + "saved_object:ingest-package-policies/create", + "saved_object:ingest-package-policies/bulk_create", + "saved_object:ingest-package-policies/update", + "saved_object:ingest-package-policies/bulk_update", + "saved_object:ingest-package-policies/delete", + "saved_object:ingest-package-policies/bulk_delete", + "saved_object:ingest-package-policies/share_to_space", + "saved_object:epm-packages/bulk_get", + "saved_object:epm-packages/get", + "saved_object:epm-packages/find", + "saved_object:epm-packages/open_point_in_time", + "saved_object:epm-packages/close_point_in_time", + "saved_object:epm-packages/create", + "saved_object:epm-packages/bulk_create", + "saved_object:epm-packages/update", + "saved_object:epm-packages/bulk_update", + "saved_object:epm-packages/delete", + "saved_object:epm-packages/bulk_delete", + "saved_object:epm-packages/share_to_space", + "saved_object:epm-packages-assets/bulk_get", + "saved_object:epm-packages-assets/get", + "saved_object:epm-packages-assets/find", + "saved_object:epm-packages-assets/open_point_in_time", + "saved_object:epm-packages-assets/close_point_in_time", + "saved_object:epm-packages-assets/create", + "saved_object:epm-packages-assets/bulk_create", + "saved_object:epm-packages-assets/update", + "saved_object:epm-packages-assets/bulk_update", + "saved_object:epm-packages-assets/delete", + "saved_object:epm-packages-assets/bulk_delete", + "saved_object:epm-packages-assets/share_to_space", + "saved_object:fleet-preconfiguration-deletion-record/bulk_get", + "saved_object:fleet-preconfiguration-deletion-record/get", + "saved_object:fleet-preconfiguration-deletion-record/find", + "saved_object:fleet-preconfiguration-deletion-record/open_point_in_time", + "saved_object:fleet-preconfiguration-deletion-record/close_point_in_time", + "saved_object:fleet-preconfiguration-deletion-record/create", + "saved_object:fleet-preconfiguration-deletion-record/bulk_create", + "saved_object:fleet-preconfiguration-deletion-record/update", + "saved_object:fleet-preconfiguration-deletion-record/bulk_update", + "saved_object:fleet-preconfiguration-deletion-record/delete", + "saved_object:fleet-preconfiguration-deletion-record/bulk_delete", + "saved_object:fleet-preconfiguration-deletion-record/share_to_space", + "saved_object:ingest-download-sources/bulk_get", + "saved_object:ingest-download-sources/get", + "saved_object:ingest-download-sources/find", + "saved_object:ingest-download-sources/open_point_in_time", + "saved_object:ingest-download-sources/close_point_in_time", + "saved_object:ingest-download-sources/create", + "saved_object:ingest-download-sources/bulk_create", + "saved_object:ingest-download-sources/update", + "saved_object:ingest-download-sources/bulk_update", + "saved_object:ingest-download-sources/delete", + "saved_object:ingest-download-sources/bulk_delete", + "saved_object:ingest-download-sources/share_to_space", + "saved_object:fleet-fleet-server-host/bulk_get", + "saved_object:fleet-fleet-server-host/get", + "saved_object:fleet-fleet-server-host/find", + "saved_object:fleet-fleet-server-host/open_point_in_time", + "saved_object:fleet-fleet-server-host/close_point_in_time", + "saved_object:fleet-fleet-server-host/create", + "saved_object:fleet-fleet-server-host/bulk_create", + "saved_object:fleet-fleet-server-host/update", + "saved_object:fleet-fleet-server-host/bulk_update", + "saved_object:fleet-fleet-server-host/delete", + "saved_object:fleet-fleet-server-host/bulk_delete", + "saved_object:fleet-fleet-server-host/share_to_space", + "saved_object:fleet-proxy/bulk_get", + "saved_object:fleet-proxy/get", + "saved_object:fleet-proxy/find", + "saved_object:fleet-proxy/open_point_in_time", + "saved_object:fleet-proxy/close_point_in_time", + "saved_object:fleet-proxy/create", + "saved_object:fleet-proxy/bulk_create", + "saved_object:fleet-proxy/update", + "saved_object:fleet-proxy/bulk_update", + "saved_object:fleet-proxy/delete", + "saved_object:fleet-proxy/bulk_delete", + "saved_object:fleet-proxy/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:fleetv2/read", + "ui:fleetv2/all", + "api:infra", + "api:rac", + "app:infra", + "app:logs", + "app:kibana", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/infra", + "ui:navLinks/logs", + "ui:navLinks/kibana", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-ui-source/create", + "saved_object:infrastructure-ui-source/bulk_create", + "saved_object:infrastructure-ui-source/update", + "saved_object:infrastructure-ui-source/bulk_update", + "saved_object:infrastructure-ui-source/delete", + "saved_object:infrastructure-ui-source/bulk_delete", + "saved_object:infrastructure-ui-source/share_to_space", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/create", + "saved_object:infrastructure-monitoring-log-view/bulk_create", + "saved_object:infrastructure-monitoring-log-view/update", + "saved_object:infrastructure-monitoring-log-view/bulk_update", + "saved_object:infrastructure-monitoring-log-view/delete", + "saved_object:infrastructure-monitoring-log-view/bulk_delete", + "saved_object:infrastructure-monitoring-log-view/share_to_space", + "ui:logs/show", + "ui:logs/configureSource", + "ui:logs/save", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/rule/create", + "alerting:logs.alert.document.count/logs/rule/delete", + "alerting:logs.alert.document.count/logs/rule/update", + "alerting:logs.alert.document.count/logs/rule/updateApiKey", + "alerting:logs.alert.document.count/logs/rule/enable", + "alerting:logs.alert.document.count/logs/rule/disable", + "alerting:logs.alert.document.count/logs/rule/muteAll", + "alerting:logs.alert.document.count/logs/rule/unmuteAll", + "alerting:logs.alert.document.count/logs/rule/muteAlert", + "alerting:logs.alert.document.count/logs/rule/unmuteAlert", + "alerting:logs.alert.document.count/logs/rule/snooze", + "alerting:logs.alert.document.count/logs/rule/bulkEdit", + "alerting:logs.alert.document.count/logs/rule/bulkDelete", + "alerting:logs.alert.document.count/logs/rule/bulkEnable", + "alerting:logs.alert.document.count/logs/rule/bulkDisable", + "alerting:logs.alert.document.count/logs/rule/unsnooze", + "alerting:logs.alert.document.count/logs/rule/runSoon", + "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", + "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/create", + "alerting:.es-query/logs/rule/delete", + "alerting:.es-query/logs/rule/update", + "alerting:.es-query/logs/rule/updateApiKey", + "alerting:.es-query/logs/rule/enable", + "alerting:.es-query/logs/rule/disable", + "alerting:.es-query/logs/rule/muteAll", + "alerting:.es-query/logs/rule/unmuteAll", + "alerting:.es-query/logs/rule/muteAlert", + "alerting:.es-query/logs/rule/unmuteAlert", + "alerting:.es-query/logs/rule/snooze", + "alerting:.es-query/logs/rule/bulkEdit", + "alerting:.es-query/logs/rule/bulkDelete", + "alerting:.es-query/logs/rule/bulkEnable", + "alerting:.es-query/logs/rule/bulkDisable", + "alerting:.es-query/logs/rule/unsnooze", + "alerting:.es-query/logs/rule/runSoon", + "alerting:.es-query/logs/rule/scheduleBackfill", + "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/create", + "alerting:observability.rules.custom_threshold/logs/rule/delete", + "alerting:observability.rules.custom_threshold/logs/rule/update", + "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/logs/rule/enable", + "alerting:observability.rules.custom_threshold/logs/rule/disable", + "alerting:observability.rules.custom_threshold/logs/rule/muteAll", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/snooze", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", + "alerting:observability.rules.custom_threshold/logs/rule/runSoon", + "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/logs/alert/update", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/update", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + ], + "minimal_all": Array [ + "login:", + "api:fleet-read", + "api:fleet-all", + "app:fleet", + "ui:catalogue/fleet", + "ui:navLinks/fleet", + "saved_object:ingest-outputs/bulk_get", + "saved_object:ingest-outputs/get", + "saved_object:ingest-outputs/find", + "saved_object:ingest-outputs/open_point_in_time", + "saved_object:ingest-outputs/close_point_in_time", + "saved_object:ingest-outputs/create", + "saved_object:ingest-outputs/bulk_create", + "saved_object:ingest-outputs/update", + "saved_object:ingest-outputs/bulk_update", + "saved_object:ingest-outputs/delete", + "saved_object:ingest-outputs/bulk_delete", + "saved_object:ingest-outputs/share_to_space", + "saved_object:ingest-agent-policies/bulk_get", + "saved_object:ingest-agent-policies/get", + "saved_object:ingest-agent-policies/find", + "saved_object:ingest-agent-policies/open_point_in_time", + "saved_object:ingest-agent-policies/close_point_in_time", + "saved_object:ingest-agent-policies/create", + "saved_object:ingest-agent-policies/bulk_create", + "saved_object:ingest-agent-policies/update", + "saved_object:ingest-agent-policies/bulk_update", + "saved_object:ingest-agent-policies/delete", + "saved_object:ingest-agent-policies/bulk_delete", + "saved_object:ingest-agent-policies/share_to_space", + "saved_object:ingest-package-policies/bulk_get", + "saved_object:ingest-package-policies/get", + "saved_object:ingest-package-policies/find", + "saved_object:ingest-package-policies/open_point_in_time", + "saved_object:ingest-package-policies/close_point_in_time", + "saved_object:ingest-package-policies/create", + "saved_object:ingest-package-policies/bulk_create", + "saved_object:ingest-package-policies/update", + "saved_object:ingest-package-policies/bulk_update", + "saved_object:ingest-package-policies/delete", + "saved_object:ingest-package-policies/bulk_delete", + "saved_object:ingest-package-policies/share_to_space", + "saved_object:epm-packages/bulk_get", + "saved_object:epm-packages/get", + "saved_object:epm-packages/find", + "saved_object:epm-packages/open_point_in_time", + "saved_object:epm-packages/close_point_in_time", + "saved_object:epm-packages/create", + "saved_object:epm-packages/bulk_create", + "saved_object:epm-packages/update", + "saved_object:epm-packages/bulk_update", + "saved_object:epm-packages/delete", + "saved_object:epm-packages/bulk_delete", + "saved_object:epm-packages/share_to_space", + "saved_object:epm-packages-assets/bulk_get", + "saved_object:epm-packages-assets/get", + "saved_object:epm-packages-assets/find", + "saved_object:epm-packages-assets/open_point_in_time", + "saved_object:epm-packages-assets/close_point_in_time", + "saved_object:epm-packages-assets/create", + "saved_object:epm-packages-assets/bulk_create", + "saved_object:epm-packages-assets/update", + "saved_object:epm-packages-assets/bulk_update", + "saved_object:epm-packages-assets/delete", + "saved_object:epm-packages-assets/bulk_delete", + "saved_object:epm-packages-assets/share_to_space", + "saved_object:fleet-preconfiguration-deletion-record/bulk_get", + "saved_object:fleet-preconfiguration-deletion-record/get", + "saved_object:fleet-preconfiguration-deletion-record/find", + "saved_object:fleet-preconfiguration-deletion-record/open_point_in_time", + "saved_object:fleet-preconfiguration-deletion-record/close_point_in_time", + "saved_object:fleet-preconfiguration-deletion-record/create", + "saved_object:fleet-preconfiguration-deletion-record/bulk_create", + "saved_object:fleet-preconfiguration-deletion-record/update", + "saved_object:fleet-preconfiguration-deletion-record/bulk_update", + "saved_object:fleet-preconfiguration-deletion-record/delete", + "saved_object:fleet-preconfiguration-deletion-record/bulk_delete", + "saved_object:fleet-preconfiguration-deletion-record/share_to_space", + "saved_object:ingest-download-sources/bulk_get", + "saved_object:ingest-download-sources/get", + "saved_object:ingest-download-sources/find", + "saved_object:ingest-download-sources/open_point_in_time", + "saved_object:ingest-download-sources/close_point_in_time", + "saved_object:ingest-download-sources/create", + "saved_object:ingest-download-sources/bulk_create", + "saved_object:ingest-download-sources/update", + "saved_object:ingest-download-sources/bulk_update", + "saved_object:ingest-download-sources/delete", + "saved_object:ingest-download-sources/bulk_delete", + "saved_object:ingest-download-sources/share_to_space", + "saved_object:fleet-fleet-server-host/bulk_get", + "saved_object:fleet-fleet-server-host/get", + "saved_object:fleet-fleet-server-host/find", + "saved_object:fleet-fleet-server-host/open_point_in_time", + "saved_object:fleet-fleet-server-host/close_point_in_time", + "saved_object:fleet-fleet-server-host/create", + "saved_object:fleet-fleet-server-host/bulk_create", + "saved_object:fleet-fleet-server-host/update", + "saved_object:fleet-fleet-server-host/bulk_update", + "saved_object:fleet-fleet-server-host/delete", + "saved_object:fleet-fleet-server-host/bulk_delete", + "saved_object:fleet-fleet-server-host/share_to_space", + "saved_object:fleet-proxy/bulk_get", + "saved_object:fleet-proxy/get", + "saved_object:fleet-proxy/find", + "saved_object:fleet-proxy/open_point_in_time", + "saved_object:fleet-proxy/close_point_in_time", + "saved_object:fleet-proxy/create", + "saved_object:fleet-proxy/bulk_create", + "saved_object:fleet-proxy/update", + "saved_object:fleet-proxy/bulk_update", + "saved_object:fleet-proxy/delete", + "saved_object:fleet-proxy/bulk_delete", + "saved_object:fleet-proxy/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:fleetv2/read", + "ui:fleetv2/all", + "api:infra", + "api:rac", + "app:infra", + "app:logs", + "app:kibana", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/infra", + "ui:navLinks/logs", + "ui:navLinks/kibana", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-ui-source/create", + "saved_object:infrastructure-ui-source/bulk_create", + "saved_object:infrastructure-ui-source/update", + "saved_object:infrastructure-ui-source/bulk_update", + "saved_object:infrastructure-ui-source/delete", + "saved_object:infrastructure-ui-source/bulk_delete", + "saved_object:infrastructure-ui-source/share_to_space", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/create", + "saved_object:infrastructure-monitoring-log-view/bulk_create", + "saved_object:infrastructure-monitoring-log-view/update", + "saved_object:infrastructure-monitoring-log-view/bulk_update", + "saved_object:infrastructure-monitoring-log-view/delete", + "saved_object:infrastructure-monitoring-log-view/bulk_delete", + "saved_object:infrastructure-monitoring-log-view/share_to_space", + "ui:logs/show", + "ui:logs/configureSource", + "ui:logs/save", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/rule/create", + "alerting:logs.alert.document.count/logs/rule/delete", + "alerting:logs.alert.document.count/logs/rule/update", + "alerting:logs.alert.document.count/logs/rule/updateApiKey", + "alerting:logs.alert.document.count/logs/rule/enable", + "alerting:logs.alert.document.count/logs/rule/disable", + "alerting:logs.alert.document.count/logs/rule/muteAll", + "alerting:logs.alert.document.count/logs/rule/unmuteAll", + "alerting:logs.alert.document.count/logs/rule/muteAlert", + "alerting:logs.alert.document.count/logs/rule/unmuteAlert", + "alerting:logs.alert.document.count/logs/rule/snooze", + "alerting:logs.alert.document.count/logs/rule/bulkEdit", + "alerting:logs.alert.document.count/logs/rule/bulkDelete", + "alerting:logs.alert.document.count/logs/rule/bulkEnable", + "alerting:logs.alert.document.count/logs/rule/bulkDisable", + "alerting:logs.alert.document.count/logs/rule/unsnooze", + "alerting:logs.alert.document.count/logs/rule/runSoon", + "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", + "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/create", + "alerting:.es-query/logs/rule/delete", + "alerting:.es-query/logs/rule/update", + "alerting:.es-query/logs/rule/updateApiKey", + "alerting:.es-query/logs/rule/enable", + "alerting:.es-query/logs/rule/disable", + "alerting:.es-query/logs/rule/muteAll", + "alerting:.es-query/logs/rule/unmuteAll", + "alerting:.es-query/logs/rule/muteAlert", + "alerting:.es-query/logs/rule/unmuteAlert", + "alerting:.es-query/logs/rule/snooze", + "alerting:.es-query/logs/rule/bulkEdit", + "alerting:.es-query/logs/rule/bulkDelete", + "alerting:.es-query/logs/rule/bulkEnable", + "alerting:.es-query/logs/rule/bulkDisable", + "alerting:.es-query/logs/rule/unsnooze", + "alerting:.es-query/logs/rule/runSoon", + "alerting:.es-query/logs/rule/scheduleBackfill", + "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/create", + "alerting:observability.rules.custom_threshold/logs/rule/delete", + "alerting:observability.rules.custom_threshold/logs/rule/update", + "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/logs/rule/enable", + "alerting:observability.rules.custom_threshold/logs/rule/disable", + "alerting:observability.rules.custom_threshold/logs/rule/muteAll", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/snooze", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", + "alerting:observability.rules.custom_threshold/logs/rule/runSoon", + "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/logs/alert/update", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/update", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + ], + "minimal_read": Array [ + "login:", + "api:fleet-read", + "app:fleet", + "ui:catalogue/fleet", + "ui:navLinks/fleet", + "saved_object:ingest-outputs/bulk_get", + "saved_object:ingest-outputs/get", + "saved_object:ingest-outputs/find", + "saved_object:ingest-outputs/open_point_in_time", + "saved_object:ingest-outputs/close_point_in_time", + "saved_object:ingest-agent-policies/bulk_get", + "saved_object:ingest-agent-policies/get", + "saved_object:ingest-agent-policies/find", + "saved_object:ingest-agent-policies/open_point_in_time", + "saved_object:ingest-agent-policies/close_point_in_time", + "saved_object:ingest-package-policies/bulk_get", + "saved_object:ingest-package-policies/get", + "saved_object:ingest-package-policies/find", + "saved_object:ingest-package-policies/open_point_in_time", + "saved_object:ingest-package-policies/close_point_in_time", + "saved_object:epm-packages/bulk_get", + "saved_object:epm-packages/get", + "saved_object:epm-packages/find", + "saved_object:epm-packages/open_point_in_time", + "saved_object:epm-packages/close_point_in_time", + "saved_object:epm-packages-assets/bulk_get", + "saved_object:epm-packages-assets/get", + "saved_object:epm-packages-assets/find", + "saved_object:epm-packages-assets/open_point_in_time", + "saved_object:epm-packages-assets/close_point_in_time", + "saved_object:fleet-preconfiguration-deletion-record/bulk_get", + "saved_object:fleet-preconfiguration-deletion-record/get", + "saved_object:fleet-preconfiguration-deletion-record/find", + "saved_object:fleet-preconfiguration-deletion-record/open_point_in_time", + "saved_object:fleet-preconfiguration-deletion-record/close_point_in_time", + "saved_object:ingest-download-sources/bulk_get", + "saved_object:ingest-download-sources/get", + "saved_object:ingest-download-sources/find", + "saved_object:ingest-download-sources/open_point_in_time", + "saved_object:ingest-download-sources/close_point_in_time", + "saved_object:fleet-fleet-server-host/bulk_get", + "saved_object:fleet-fleet-server-host/get", + "saved_object:fleet-fleet-server-host/find", + "saved_object:fleet-fleet-server-host/open_point_in_time", + "saved_object:fleet-fleet-server-host/close_point_in_time", + "saved_object:fleet-proxy/bulk_get", + "saved_object:fleet-proxy/get", + "saved_object:fleet-proxy/find", + "saved_object:fleet-proxy/open_point_in_time", + "saved_object:fleet-proxy/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:fleetv2/read", + "api:infra", + "api:rac", + "app:infra", + "app:logs", + "app:kibana", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/infra", + "ui:navLinks/logs", + "ui:navLinks/kibana", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "ui:logs/show", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + ], + "read": Array [ + "login:", + "api:fleet-read", + "app:fleet", + "ui:catalogue/fleet", + "ui:navLinks/fleet", + "saved_object:ingest-outputs/bulk_get", + "saved_object:ingest-outputs/get", + "saved_object:ingest-outputs/find", + "saved_object:ingest-outputs/open_point_in_time", + "saved_object:ingest-outputs/close_point_in_time", + "saved_object:ingest-agent-policies/bulk_get", + "saved_object:ingest-agent-policies/get", + "saved_object:ingest-agent-policies/find", + "saved_object:ingest-agent-policies/open_point_in_time", + "saved_object:ingest-agent-policies/close_point_in_time", + "saved_object:ingest-package-policies/bulk_get", + "saved_object:ingest-package-policies/get", + "saved_object:ingest-package-policies/find", + "saved_object:ingest-package-policies/open_point_in_time", + "saved_object:ingest-package-policies/close_point_in_time", + "saved_object:epm-packages/bulk_get", + "saved_object:epm-packages/get", + "saved_object:epm-packages/find", + "saved_object:epm-packages/open_point_in_time", + "saved_object:epm-packages/close_point_in_time", + "saved_object:epm-packages-assets/bulk_get", + "saved_object:epm-packages-assets/get", + "saved_object:epm-packages-assets/find", + "saved_object:epm-packages-assets/open_point_in_time", + "saved_object:epm-packages-assets/close_point_in_time", + "saved_object:fleet-preconfiguration-deletion-record/bulk_get", + "saved_object:fleet-preconfiguration-deletion-record/get", + "saved_object:fleet-preconfiguration-deletion-record/find", + "saved_object:fleet-preconfiguration-deletion-record/open_point_in_time", + "saved_object:fleet-preconfiguration-deletion-record/close_point_in_time", + "saved_object:ingest-download-sources/bulk_get", + "saved_object:ingest-download-sources/get", + "saved_object:ingest-download-sources/find", + "saved_object:ingest-download-sources/open_point_in_time", + "saved_object:ingest-download-sources/close_point_in_time", + "saved_object:fleet-fleet-server-host/bulk_get", + "saved_object:fleet-fleet-server-host/get", + "saved_object:fleet-fleet-server-host/find", + "saved_object:fleet-fleet-server-host/open_point_in_time", + "saved_object:fleet-fleet-server-host/close_point_in_time", + "saved_object:fleet-proxy/bulk_get", + "saved_object:fleet-proxy/get", + "saved_object:fleet-proxy/find", + "saved_object:fleet-proxy/open_point_in_time", + "saved_object:fleet-proxy/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:fleetv2/read", + "api:infra", + "api:rac", + "app:infra", + "app:logs", + "app:kibana", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/infra", + "ui:navLinks/logs", + "ui:navLinks/kibana", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "ui:logs/show", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + ], + }, + "infrastructure": Object { + "all": Array [ + "login:", + "api:infra", + "api:rac", + "app:infra", + "app:metrics", + "app:kibana", + "ui:catalogue/infraops", + "ui:catalogue/metrics", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/infra", + "ui:navLinks/metrics", + "ui:navLinks/kibana", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-ui-source/create", + "saved_object:infrastructure-ui-source/bulk_create", + "saved_object:infrastructure-ui-source/update", + "saved_object:infrastructure-ui-source/bulk_update", + "saved_object:infrastructure-ui-source/delete", + "saved_object:infrastructure-ui-source/bulk_delete", + "saved_object:infrastructure-ui-source/share_to_space", + "saved_object:metrics-data-source/bulk_get", + "saved_object:metrics-data-source/get", + "saved_object:metrics-data-source/find", + "saved_object:metrics-data-source/open_point_in_time", + "saved_object:metrics-data-source/close_point_in_time", + "saved_object:metrics-data-source/create", + "saved_object:metrics-data-source/bulk_create", + "saved_object:metrics-data-source/update", + "saved_object:metrics-data-source/bulk_update", + "saved_object:metrics-data-source/delete", + "saved_object:metrics-data-source/bulk_delete", + "saved_object:metrics-data-source/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:infrastructure/show", + "ui:infrastructure/configureSource", + "ui:infrastructure/save", + "alerting:metrics.alert.threshold/infrastructure/rule/get", + "alerting:metrics.alert.threshold/infrastructure/rule/getRuleState", + "alerting:metrics.alert.threshold/infrastructure/rule/getAlertSummary", + "alerting:metrics.alert.threshold/infrastructure/rule/getExecutionLog", + "alerting:metrics.alert.threshold/infrastructure/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/infrastructure/rule/find", + "alerting:metrics.alert.threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/infrastructure/rule/getBackfill", + "alerting:metrics.alert.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.threshold/infrastructure/rule/create", + "alerting:metrics.alert.threshold/infrastructure/rule/delete", + "alerting:metrics.alert.threshold/infrastructure/rule/update", + "alerting:metrics.alert.threshold/infrastructure/rule/updateApiKey", + "alerting:metrics.alert.threshold/infrastructure/rule/enable", + "alerting:metrics.alert.threshold/infrastructure/rule/disable", + "alerting:metrics.alert.threshold/infrastructure/rule/muteAll", + "alerting:metrics.alert.threshold/infrastructure/rule/unmuteAll", + "alerting:metrics.alert.threshold/infrastructure/rule/muteAlert", + "alerting:metrics.alert.threshold/infrastructure/rule/unmuteAlert", + "alerting:metrics.alert.threshold/infrastructure/rule/snooze", + "alerting:metrics.alert.threshold/infrastructure/rule/bulkEdit", + "alerting:metrics.alert.threshold/infrastructure/rule/bulkDelete", + "alerting:metrics.alert.threshold/infrastructure/rule/bulkEnable", + "alerting:metrics.alert.threshold/infrastructure/rule/bulkDisable", + "alerting:metrics.alert.threshold/infrastructure/rule/unsnooze", + "alerting:metrics.alert.threshold/infrastructure/rule/runSoon", + "alerting:metrics.alert.threshold/infrastructure/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/infrastructure/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/get", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/find", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/create", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/delete", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/update", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/enable", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/disable", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/snooze", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/deleteBackfill", + "alerting:.es-query/infrastructure/rule/get", + "alerting:.es-query/infrastructure/rule/getRuleState", + "alerting:.es-query/infrastructure/rule/getAlertSummary", + "alerting:.es-query/infrastructure/rule/getExecutionLog", + "alerting:.es-query/infrastructure/rule/getActionErrorLog", + "alerting:.es-query/infrastructure/rule/find", + "alerting:.es-query/infrastructure/rule/getRuleExecutionKPI", + "alerting:.es-query/infrastructure/rule/getBackfill", + "alerting:.es-query/infrastructure/rule/findBackfill", + "alerting:.es-query/infrastructure/rule/create", + "alerting:.es-query/infrastructure/rule/delete", + "alerting:.es-query/infrastructure/rule/update", + "alerting:.es-query/infrastructure/rule/updateApiKey", + "alerting:.es-query/infrastructure/rule/enable", + "alerting:.es-query/infrastructure/rule/disable", + "alerting:.es-query/infrastructure/rule/muteAll", + "alerting:.es-query/infrastructure/rule/unmuteAll", + "alerting:.es-query/infrastructure/rule/muteAlert", + "alerting:.es-query/infrastructure/rule/unmuteAlert", + "alerting:.es-query/infrastructure/rule/snooze", + "alerting:.es-query/infrastructure/rule/bulkEdit", + "alerting:.es-query/infrastructure/rule/bulkDelete", + "alerting:.es-query/infrastructure/rule/bulkEnable", + "alerting:.es-query/infrastructure/rule/bulkDisable", + "alerting:.es-query/infrastructure/rule/unsnooze", + "alerting:.es-query/infrastructure/rule/runSoon", + "alerting:.es-query/infrastructure/rule/scheduleBackfill", + "alerting:.es-query/infrastructure/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/get", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleState", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/infrastructure/rule/find", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/findBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/create", + "alerting:observability.rules.custom_threshold/infrastructure/rule/delete", + "alerting:observability.rules.custom_threshold/infrastructure/rule/update", + "alerting:observability.rules.custom_threshold/infrastructure/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/infrastructure/rule/enable", + "alerting:observability.rules.custom_threshold/infrastructure/rule/disable", + "alerting:observability.rules.custom_threshold/infrastructure/rule/muteAll", + "alerting:observability.rules.custom_threshold/infrastructure/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/infrastructure/rule/muteAlert", + "alerting:observability.rules.custom_threshold/infrastructure/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/infrastructure/rule/snooze", + "alerting:observability.rules.custom_threshold/infrastructure/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/infrastructure/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/infrastructure/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/infrastructure/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/infrastructure/rule/unsnooze", + "alerting:observability.rules.custom_threshold/infrastructure/rule/runSoon", + "alerting:observability.rules.custom_threshold/infrastructure/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/deleteBackfill", + "alerting:metrics.alert.threshold/infrastructure/alert/get", + "alerting:metrics.alert.threshold/infrastructure/alert/find", + "alerting:metrics.alert.threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.threshold/infrastructure/alert/update", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/get", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/find", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/update", + "alerting:.es-query/infrastructure/alert/get", + "alerting:.es-query/infrastructure/alert/find", + "alerting:.es-query/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/infrastructure/alert/getAlertSummary", + "alerting:.es-query/infrastructure/alert/update", + "alerting:observability.rules.custom_threshold/infrastructure/alert/get", + "alerting:observability.rules.custom_threshold/infrastructure/alert/find", + "alerting:observability.rules.custom_threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/infrastructure/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/infrastructure/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/update", + "app:logs", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:navLinks/logs", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/create", + "saved_object:infrastructure-monitoring-log-view/bulk_create", + "saved_object:infrastructure-monitoring-log-view/update", + "saved_object:infrastructure-monitoring-log-view/bulk_update", + "saved_object:infrastructure-monitoring-log-view/delete", + "saved_object:infrastructure-monitoring-log-view/bulk_delete", + "saved_object:infrastructure-monitoring-log-view/share_to_space", + "ui:logs/show", + "ui:logs/configureSource", + "ui:logs/save", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/rule/create", + "alerting:logs.alert.document.count/logs/rule/delete", + "alerting:logs.alert.document.count/logs/rule/update", + "alerting:logs.alert.document.count/logs/rule/updateApiKey", + "alerting:logs.alert.document.count/logs/rule/enable", + "alerting:logs.alert.document.count/logs/rule/disable", + "alerting:logs.alert.document.count/logs/rule/muteAll", + "alerting:logs.alert.document.count/logs/rule/unmuteAll", + "alerting:logs.alert.document.count/logs/rule/muteAlert", + "alerting:logs.alert.document.count/logs/rule/unmuteAlert", + "alerting:logs.alert.document.count/logs/rule/snooze", + "alerting:logs.alert.document.count/logs/rule/bulkEdit", + "alerting:logs.alert.document.count/logs/rule/bulkDelete", + "alerting:logs.alert.document.count/logs/rule/bulkEnable", + "alerting:logs.alert.document.count/logs/rule/bulkDisable", + "alerting:logs.alert.document.count/logs/rule/unsnooze", + "alerting:logs.alert.document.count/logs/rule/runSoon", + "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", + "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/create", + "alerting:.es-query/logs/rule/delete", + "alerting:.es-query/logs/rule/update", + "alerting:.es-query/logs/rule/updateApiKey", + "alerting:.es-query/logs/rule/enable", + "alerting:.es-query/logs/rule/disable", + "alerting:.es-query/logs/rule/muteAll", + "alerting:.es-query/logs/rule/unmuteAll", + "alerting:.es-query/logs/rule/muteAlert", + "alerting:.es-query/logs/rule/unmuteAlert", + "alerting:.es-query/logs/rule/snooze", + "alerting:.es-query/logs/rule/bulkEdit", + "alerting:.es-query/logs/rule/bulkDelete", + "alerting:.es-query/logs/rule/bulkEnable", + "alerting:.es-query/logs/rule/bulkDisable", + "alerting:.es-query/logs/rule/unsnooze", + "alerting:.es-query/logs/rule/runSoon", + "alerting:.es-query/logs/rule/scheduleBackfill", + "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/create", + "alerting:observability.rules.custom_threshold/logs/rule/delete", + "alerting:observability.rules.custom_threshold/logs/rule/update", + "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/logs/rule/enable", + "alerting:observability.rules.custom_threshold/logs/rule/disable", + "alerting:observability.rules.custom_threshold/logs/rule/muteAll", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/snooze", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", + "alerting:observability.rules.custom_threshold/logs/rule/runSoon", + "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/logs/alert/update", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/update", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "minimal_all": Array [ + "login:", + "api:infra", + "api:rac", + "app:infra", + "app:metrics", + "app:kibana", + "ui:catalogue/infraops", + "ui:catalogue/metrics", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/infra", + "ui:navLinks/metrics", + "ui:navLinks/kibana", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:infrastructure-ui-source/create", + "saved_object:infrastructure-ui-source/bulk_create", + "saved_object:infrastructure-ui-source/update", + "saved_object:infrastructure-ui-source/bulk_update", + "saved_object:infrastructure-ui-source/delete", + "saved_object:infrastructure-ui-source/bulk_delete", + "saved_object:infrastructure-ui-source/share_to_space", + "saved_object:metrics-data-source/bulk_get", + "saved_object:metrics-data-source/get", + "saved_object:metrics-data-source/find", + "saved_object:metrics-data-source/open_point_in_time", + "saved_object:metrics-data-source/close_point_in_time", + "saved_object:metrics-data-source/create", + "saved_object:metrics-data-source/bulk_create", + "saved_object:metrics-data-source/update", + "saved_object:metrics-data-source/bulk_update", + "saved_object:metrics-data-source/delete", + "saved_object:metrics-data-source/bulk_delete", + "saved_object:metrics-data-source/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:infrastructure/show", + "ui:infrastructure/configureSource", + "ui:infrastructure/save", + "alerting:metrics.alert.threshold/infrastructure/rule/get", + "alerting:metrics.alert.threshold/infrastructure/rule/getRuleState", + "alerting:metrics.alert.threshold/infrastructure/rule/getAlertSummary", + "alerting:metrics.alert.threshold/infrastructure/rule/getExecutionLog", + "alerting:metrics.alert.threshold/infrastructure/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/infrastructure/rule/find", + "alerting:metrics.alert.threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/infrastructure/rule/getBackfill", + "alerting:metrics.alert.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.threshold/infrastructure/rule/create", + "alerting:metrics.alert.threshold/infrastructure/rule/delete", + "alerting:metrics.alert.threshold/infrastructure/rule/update", + "alerting:metrics.alert.threshold/infrastructure/rule/updateApiKey", + "alerting:metrics.alert.threshold/infrastructure/rule/enable", + "alerting:metrics.alert.threshold/infrastructure/rule/disable", + "alerting:metrics.alert.threshold/infrastructure/rule/muteAll", + "alerting:metrics.alert.threshold/infrastructure/rule/unmuteAll", + "alerting:metrics.alert.threshold/infrastructure/rule/muteAlert", + "alerting:metrics.alert.threshold/infrastructure/rule/unmuteAlert", + "alerting:metrics.alert.threshold/infrastructure/rule/snooze", + "alerting:metrics.alert.threshold/infrastructure/rule/bulkEdit", + "alerting:metrics.alert.threshold/infrastructure/rule/bulkDelete", + "alerting:metrics.alert.threshold/infrastructure/rule/bulkEnable", + "alerting:metrics.alert.threshold/infrastructure/rule/bulkDisable", + "alerting:metrics.alert.threshold/infrastructure/rule/unsnooze", + "alerting:metrics.alert.threshold/infrastructure/rule/runSoon", + "alerting:metrics.alert.threshold/infrastructure/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/infrastructure/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/get", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/find", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/create", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/delete", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/update", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/enable", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/disable", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/snooze", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/deleteBackfill", + "alerting:.es-query/infrastructure/rule/get", + "alerting:.es-query/infrastructure/rule/getRuleState", + "alerting:.es-query/infrastructure/rule/getAlertSummary", + "alerting:.es-query/infrastructure/rule/getExecutionLog", + "alerting:.es-query/infrastructure/rule/getActionErrorLog", + "alerting:.es-query/infrastructure/rule/find", + "alerting:.es-query/infrastructure/rule/getRuleExecutionKPI", + "alerting:.es-query/infrastructure/rule/getBackfill", + "alerting:.es-query/infrastructure/rule/findBackfill", + "alerting:.es-query/infrastructure/rule/create", + "alerting:.es-query/infrastructure/rule/delete", + "alerting:.es-query/infrastructure/rule/update", + "alerting:.es-query/infrastructure/rule/updateApiKey", + "alerting:.es-query/infrastructure/rule/enable", + "alerting:.es-query/infrastructure/rule/disable", + "alerting:.es-query/infrastructure/rule/muteAll", + "alerting:.es-query/infrastructure/rule/unmuteAll", + "alerting:.es-query/infrastructure/rule/muteAlert", + "alerting:.es-query/infrastructure/rule/unmuteAlert", + "alerting:.es-query/infrastructure/rule/snooze", + "alerting:.es-query/infrastructure/rule/bulkEdit", + "alerting:.es-query/infrastructure/rule/bulkDelete", + "alerting:.es-query/infrastructure/rule/bulkEnable", + "alerting:.es-query/infrastructure/rule/bulkDisable", + "alerting:.es-query/infrastructure/rule/unsnooze", + "alerting:.es-query/infrastructure/rule/runSoon", + "alerting:.es-query/infrastructure/rule/scheduleBackfill", + "alerting:.es-query/infrastructure/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/get", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleState", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/infrastructure/rule/find", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/findBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/create", + "alerting:observability.rules.custom_threshold/infrastructure/rule/delete", + "alerting:observability.rules.custom_threshold/infrastructure/rule/update", + "alerting:observability.rules.custom_threshold/infrastructure/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/infrastructure/rule/enable", + "alerting:observability.rules.custom_threshold/infrastructure/rule/disable", + "alerting:observability.rules.custom_threshold/infrastructure/rule/muteAll", + "alerting:observability.rules.custom_threshold/infrastructure/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/infrastructure/rule/muteAlert", + "alerting:observability.rules.custom_threshold/infrastructure/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/infrastructure/rule/snooze", + "alerting:observability.rules.custom_threshold/infrastructure/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/infrastructure/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/infrastructure/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/infrastructure/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/infrastructure/rule/unsnooze", + "alerting:observability.rules.custom_threshold/infrastructure/rule/runSoon", + "alerting:observability.rules.custom_threshold/infrastructure/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/deleteBackfill", + "alerting:metrics.alert.threshold/infrastructure/alert/get", + "alerting:metrics.alert.threshold/infrastructure/alert/find", + "alerting:metrics.alert.threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.threshold/infrastructure/alert/update", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/get", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/find", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/update", + "alerting:.es-query/infrastructure/alert/get", + "alerting:.es-query/infrastructure/alert/find", + "alerting:.es-query/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/infrastructure/alert/getAlertSummary", + "alerting:.es-query/infrastructure/alert/update", + "alerting:observability.rules.custom_threshold/infrastructure/alert/get", + "alerting:observability.rules.custom_threshold/infrastructure/alert/find", + "alerting:observability.rules.custom_threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/infrastructure/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/infrastructure/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/update", + "app:logs", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:navLinks/logs", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "saved_object:infrastructure-monitoring-log-view/create", + "saved_object:infrastructure-monitoring-log-view/bulk_create", + "saved_object:infrastructure-monitoring-log-view/update", + "saved_object:infrastructure-monitoring-log-view/bulk_update", + "saved_object:infrastructure-monitoring-log-view/delete", + "saved_object:infrastructure-monitoring-log-view/bulk_delete", + "saved_object:infrastructure-monitoring-log-view/share_to_space", + "ui:logs/show", + "ui:logs/configureSource", + "ui:logs/save", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/rule/create", + "alerting:logs.alert.document.count/logs/rule/delete", + "alerting:logs.alert.document.count/logs/rule/update", + "alerting:logs.alert.document.count/logs/rule/updateApiKey", + "alerting:logs.alert.document.count/logs/rule/enable", + "alerting:logs.alert.document.count/logs/rule/disable", + "alerting:logs.alert.document.count/logs/rule/muteAll", + "alerting:logs.alert.document.count/logs/rule/unmuteAll", + "alerting:logs.alert.document.count/logs/rule/muteAlert", + "alerting:logs.alert.document.count/logs/rule/unmuteAlert", + "alerting:logs.alert.document.count/logs/rule/snooze", + "alerting:logs.alert.document.count/logs/rule/bulkEdit", + "alerting:logs.alert.document.count/logs/rule/bulkDelete", + "alerting:logs.alert.document.count/logs/rule/bulkEnable", + "alerting:logs.alert.document.count/logs/rule/bulkDisable", + "alerting:logs.alert.document.count/logs/rule/unsnooze", + "alerting:logs.alert.document.count/logs/rule/runSoon", + "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", + "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/create", + "alerting:.es-query/logs/rule/delete", + "alerting:.es-query/logs/rule/update", + "alerting:.es-query/logs/rule/updateApiKey", + "alerting:.es-query/logs/rule/enable", + "alerting:.es-query/logs/rule/disable", + "alerting:.es-query/logs/rule/muteAll", + "alerting:.es-query/logs/rule/unmuteAll", + "alerting:.es-query/logs/rule/muteAlert", + "alerting:.es-query/logs/rule/unmuteAlert", + "alerting:.es-query/logs/rule/snooze", + "alerting:.es-query/logs/rule/bulkEdit", + "alerting:.es-query/logs/rule/bulkDelete", + "alerting:.es-query/logs/rule/bulkEnable", + "alerting:.es-query/logs/rule/bulkDisable", + "alerting:.es-query/logs/rule/unsnooze", + "alerting:.es-query/logs/rule/runSoon", + "alerting:.es-query/logs/rule/scheduleBackfill", + "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/create", + "alerting:observability.rules.custom_threshold/logs/rule/delete", + "alerting:observability.rules.custom_threshold/logs/rule/update", + "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/logs/rule/enable", + "alerting:observability.rules.custom_threshold/logs/rule/disable", + "alerting:observability.rules.custom_threshold/logs/rule/muteAll", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/snooze", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", + "alerting:observability.rules.custom_threshold/logs/rule/runSoon", + "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/logs/alert/update", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/update", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "minimal_read": Array [ + "login:", + "api:infra", + "api:rac", + "app:infra", + "app:metrics", + "app:kibana", + "ui:catalogue/infraops", + "ui:catalogue/metrics", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/infra", + "ui:navLinks/metrics", + "ui:navLinks/kibana", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:metrics-data-source/bulk_get", + "saved_object:metrics-data-source/get", + "saved_object:metrics-data-source/find", + "saved_object:metrics-data-source/open_point_in_time", + "saved_object:metrics-data-source/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:infrastructure/show", + "alerting:metrics.alert.threshold/infrastructure/rule/get", + "alerting:metrics.alert.threshold/infrastructure/rule/getRuleState", + "alerting:metrics.alert.threshold/infrastructure/rule/getAlertSummary", + "alerting:metrics.alert.threshold/infrastructure/rule/getExecutionLog", + "alerting:metrics.alert.threshold/infrastructure/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/infrastructure/rule/find", + "alerting:metrics.alert.threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/infrastructure/rule/getBackfill", + "alerting:metrics.alert.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/get", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/find", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/findBackfill", + "alerting:.es-query/infrastructure/rule/get", + "alerting:.es-query/infrastructure/rule/getRuleState", + "alerting:.es-query/infrastructure/rule/getAlertSummary", + "alerting:.es-query/infrastructure/rule/getExecutionLog", + "alerting:.es-query/infrastructure/rule/getActionErrorLog", + "alerting:.es-query/infrastructure/rule/find", + "alerting:.es-query/infrastructure/rule/getRuleExecutionKPI", + "alerting:.es-query/infrastructure/rule/getBackfill", + "alerting:.es-query/infrastructure/rule/findBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/get", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleState", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/infrastructure/rule/find", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/findBackfill", + "alerting:metrics.alert.threshold/infrastructure/alert/get", + "alerting:metrics.alert.threshold/infrastructure/alert/find", + "alerting:metrics.alert.threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/get", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/find", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAlertSummary", + "alerting:.es-query/infrastructure/alert/get", + "alerting:.es-query/infrastructure/alert/find", + "alerting:.es-query/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/infrastructure/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/infrastructure/alert/get", + "alerting:observability.rules.custom_threshold/infrastructure/alert/find", + "alerting:observability.rules.custom_threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/infrastructure/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAlertSummary", + "app:logs", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:navLinks/logs", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "ui:logs/show", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + "read": Array [ + "login:", + "api:infra", + "api:rac", + "app:infra", + "app:metrics", + "app:kibana", + "ui:catalogue/infraops", + "ui:catalogue/metrics", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/infra", + "ui:navLinks/metrics", + "ui:navLinks/kibana", + "saved_object:infrastructure-ui-source/bulk_get", + "saved_object:infrastructure-ui-source/get", + "saved_object:infrastructure-ui-source/find", + "saved_object:infrastructure-ui-source/open_point_in_time", + "saved_object:infrastructure-ui-source/close_point_in_time", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:metrics-data-source/bulk_get", + "saved_object:metrics-data-source/get", + "saved_object:metrics-data-source/find", + "saved_object:metrics-data-source/open_point_in_time", + "saved_object:metrics-data-source/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:infrastructure/show", + "alerting:metrics.alert.threshold/infrastructure/rule/get", + "alerting:metrics.alert.threshold/infrastructure/rule/getRuleState", + "alerting:metrics.alert.threshold/infrastructure/rule/getAlertSummary", + "alerting:metrics.alert.threshold/infrastructure/rule/getExecutionLog", + "alerting:metrics.alert.threshold/infrastructure/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/infrastructure/rule/find", + "alerting:metrics.alert.threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/infrastructure/rule/getBackfill", + "alerting:metrics.alert.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/get", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/find", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/infrastructure/rule/findBackfill", + "alerting:.es-query/infrastructure/rule/get", + "alerting:.es-query/infrastructure/rule/getRuleState", + "alerting:.es-query/infrastructure/rule/getAlertSummary", + "alerting:.es-query/infrastructure/rule/getExecutionLog", + "alerting:.es-query/infrastructure/rule/getActionErrorLog", + "alerting:.es-query/infrastructure/rule/find", + "alerting:.es-query/infrastructure/rule/getRuleExecutionKPI", + "alerting:.es-query/infrastructure/rule/getBackfill", + "alerting:.es-query/infrastructure/rule/findBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/get", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleState", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/infrastructure/rule/find", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/infrastructure/rule/getBackfill", + "alerting:observability.rules.custom_threshold/infrastructure/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/findBackfill", + "alerting:metrics.alert.threshold/infrastructure/alert/get", + "alerting:metrics.alert.threshold/infrastructure/alert/find", + "alerting:metrics.alert.threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/get", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/find", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAlertSummary", + "alerting:.es-query/infrastructure/alert/get", + "alerting:.es-query/infrastructure/alert/find", + "alerting:.es-query/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/infrastructure/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/infrastructure/alert/get", + "alerting:observability.rules.custom_threshold/infrastructure/alert/find", + "alerting:observability.rules.custom_threshold/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/infrastructure/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAlertSummary", + "app:logs", + "ui:catalogue/infralogging", + "ui:catalogue/logs", + "ui:navLinks/logs", + "saved_object:infrastructure-monitoring-log-view/bulk_get", + "saved_object:infrastructure-monitoring-log-view/get", + "saved_object:infrastructure-monitoring-log-view/find", + "saved_object:infrastructure-monitoring-log-view/open_point_in_time", + "saved_object:infrastructure-monitoring-log-view/close_point_in_time", + "ui:logs/show", + "alerting:logs.alert.document.count/logs/rule/get", + "alerting:logs.alert.document.count/logs/rule/getRuleState", + "alerting:logs.alert.document.count/logs/rule/getAlertSummary", + "alerting:logs.alert.document.count/logs/rule/getExecutionLog", + "alerting:logs.alert.document.count/logs/rule/getActionErrorLog", + "alerting:logs.alert.document.count/logs/rule/find", + "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/logs/rule/getBackfill", + "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:.es-query/logs/rule/get", + "alerting:.es-query/logs/rule/getRuleState", + "alerting:.es-query/logs/rule/getAlertSummary", + "alerting:.es-query/logs/rule/getExecutionLog", + "alerting:.es-query/logs/rule/getActionErrorLog", + "alerting:.es-query/logs/rule/find", + "alerting:.es-query/logs/rule/getRuleExecutionKPI", + "alerting:.es-query/logs/rule/getBackfill", + "alerting:.es-query/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + }, + "reporting": Object { + "all": Array [ + "login:", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "api:downloadCsv", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/downloadCsv", + "api:generateReport", + "ui:discover/generateCsv", + ], + "minimal_all": Array [ + "login:", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "api:downloadCsv", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/downloadCsv", + "api:generateReport", + "ui:discover/generateCsv", + ], + "minimal_read": Array [ + "login:", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + ], + "read": Array [ + "login:", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + ], + }, + "slo": Object { + "all": Array [ + "login:", + "api:slo_write", + "api:slo_read", + "api:rac", + "app:slo", + "app:kibana", + "ui:catalogue/slo", + "ui:catalogue/observability", + "ui:navLinks/slo", + "ui:navLinks/kibana", + "saved_object:slo/bulk_get", + "saved_object:slo/get", + "saved_object:slo/find", + "saved_object:slo/open_point_in_time", + "saved_object:slo/close_point_in_time", + "saved_object:slo/create", + "saved_object:slo/bulk_create", + "saved_object:slo/update", + "saved_object:slo/bulk_update", + "saved_object:slo/delete", + "saved_object:slo/bulk_delete", + "saved_object:slo/share_to_space", + "saved_object:slo-settings/bulk_get", + "saved_object:slo-settings/get", + "saved_object:slo-settings/find", + "saved_object:slo-settings/open_point_in_time", + "saved_object:slo-settings/close_point_in_time", + "saved_object:slo-settings/create", + "saved_object:slo-settings/bulk_create", + "saved_object:slo-settings/update", + "saved_object:slo-settings/bulk_update", + "saved_object:slo-settings/delete", + "saved_object:slo-settings/bulk_delete", + "saved_object:slo-settings/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:slo/read", + "ui:slo/write", + "alerting:slo.rules.burnRate/slo/rule/get", + "alerting:slo.rules.burnRate/slo/rule/getRuleState", + "alerting:slo.rules.burnRate/slo/rule/getAlertSummary", + "alerting:slo.rules.burnRate/slo/rule/getExecutionLog", + "alerting:slo.rules.burnRate/slo/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/slo/rule/find", + "alerting:slo.rules.burnRate/slo/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/slo/rule/getBackfill", + "alerting:slo.rules.burnRate/slo/rule/findBackfill", + "alerting:slo.rules.burnRate/slo/rule/create", + "alerting:slo.rules.burnRate/slo/rule/delete", + "alerting:slo.rules.burnRate/slo/rule/update", + "alerting:slo.rules.burnRate/slo/rule/updateApiKey", + "alerting:slo.rules.burnRate/slo/rule/enable", + "alerting:slo.rules.burnRate/slo/rule/disable", + "alerting:slo.rules.burnRate/slo/rule/muteAll", + "alerting:slo.rules.burnRate/slo/rule/unmuteAll", + "alerting:slo.rules.burnRate/slo/rule/muteAlert", + "alerting:slo.rules.burnRate/slo/rule/unmuteAlert", + "alerting:slo.rules.burnRate/slo/rule/snooze", + "alerting:slo.rules.burnRate/slo/rule/bulkEdit", + "alerting:slo.rules.burnRate/slo/rule/bulkDelete", + "alerting:slo.rules.burnRate/slo/rule/bulkEnable", + "alerting:slo.rules.burnRate/slo/rule/bulkDisable", + "alerting:slo.rules.burnRate/slo/rule/unsnooze", + "alerting:slo.rules.burnRate/slo/rule/runSoon", + "alerting:slo.rules.burnRate/slo/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/slo/rule/deleteBackfill", + "alerting:slo.rules.burnRate/slo/alert/get", + "alerting:slo.rules.burnRate/slo/alert/find", + "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", + "alerting:slo.rules.burnRate/slo/alert/update", + "app:observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "minimal_all": Array [ + "login:", + "api:slo_write", + "api:slo_read", + "api:rac", + "app:slo", + "app:kibana", + "ui:catalogue/slo", + "ui:catalogue/observability", + "ui:navLinks/slo", + "ui:navLinks/kibana", + "saved_object:slo/bulk_get", + "saved_object:slo/get", + "saved_object:slo/find", + "saved_object:slo/open_point_in_time", + "saved_object:slo/close_point_in_time", + "saved_object:slo/create", + "saved_object:slo/bulk_create", + "saved_object:slo/update", + "saved_object:slo/bulk_update", + "saved_object:slo/delete", + "saved_object:slo/bulk_delete", + "saved_object:slo/share_to_space", + "saved_object:slo-settings/bulk_get", + "saved_object:slo-settings/get", + "saved_object:slo-settings/find", + "saved_object:slo-settings/open_point_in_time", + "saved_object:slo-settings/close_point_in_time", + "saved_object:slo-settings/create", + "saved_object:slo-settings/bulk_create", + "saved_object:slo-settings/update", + "saved_object:slo-settings/bulk_update", + "saved_object:slo-settings/delete", + "saved_object:slo-settings/bulk_delete", + "saved_object:slo-settings/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:slo/read", + "ui:slo/write", + "alerting:slo.rules.burnRate/slo/rule/get", + "alerting:slo.rules.burnRate/slo/rule/getRuleState", + "alerting:slo.rules.burnRate/slo/rule/getAlertSummary", + "alerting:slo.rules.burnRate/slo/rule/getExecutionLog", + "alerting:slo.rules.burnRate/slo/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/slo/rule/find", + "alerting:slo.rules.burnRate/slo/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/slo/rule/getBackfill", + "alerting:slo.rules.burnRate/slo/rule/findBackfill", + "alerting:slo.rules.burnRate/slo/rule/create", + "alerting:slo.rules.burnRate/slo/rule/delete", + "alerting:slo.rules.burnRate/slo/rule/update", + "alerting:slo.rules.burnRate/slo/rule/updateApiKey", + "alerting:slo.rules.burnRate/slo/rule/enable", + "alerting:slo.rules.burnRate/slo/rule/disable", + "alerting:slo.rules.burnRate/slo/rule/muteAll", + "alerting:slo.rules.burnRate/slo/rule/unmuteAll", + "alerting:slo.rules.burnRate/slo/rule/muteAlert", + "alerting:slo.rules.burnRate/slo/rule/unmuteAlert", + "alerting:slo.rules.burnRate/slo/rule/snooze", + "alerting:slo.rules.burnRate/slo/rule/bulkEdit", + "alerting:slo.rules.burnRate/slo/rule/bulkDelete", + "alerting:slo.rules.burnRate/slo/rule/bulkEnable", + "alerting:slo.rules.burnRate/slo/rule/bulkDisable", + "alerting:slo.rules.burnRate/slo/rule/unsnooze", + "alerting:slo.rules.burnRate/slo/rule/runSoon", + "alerting:slo.rules.burnRate/slo/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/slo/rule/deleteBackfill", + "alerting:slo.rules.burnRate/slo/alert/get", + "alerting:slo.rules.burnRate/slo/alert/find", + "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", + "alerting:slo.rules.burnRate/slo/alert/update", + "app:observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "minimal_read": Array [ + "login:", + "api:slo_read", + "api:rac", + "app:slo", + "app:kibana", + "ui:catalogue/slo", + "ui:catalogue/observability", + "ui:navLinks/slo", + "ui:navLinks/kibana", + "saved_object:slo/bulk_get", + "saved_object:slo/get", + "saved_object:slo/find", + "saved_object:slo/open_point_in_time", + "saved_object:slo/close_point_in_time", + "saved_object:slo-settings/bulk_get", + "saved_object:slo-settings/get", + "saved_object:slo-settings/find", + "saved_object:slo-settings/open_point_in_time", + "saved_object:slo-settings/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:slo/read", + "alerting:slo.rules.burnRate/slo/rule/get", + "alerting:slo.rules.burnRate/slo/rule/getRuleState", + "alerting:slo.rules.burnRate/slo/rule/getAlertSummary", + "alerting:slo.rules.burnRate/slo/rule/getExecutionLog", + "alerting:slo.rules.burnRate/slo/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/slo/rule/find", + "alerting:slo.rules.burnRate/slo/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/slo/rule/getBackfill", + "alerting:slo.rules.burnRate/slo/rule/findBackfill", + "alerting:slo.rules.burnRate/slo/alert/get", + "alerting:slo.rules.burnRate/slo/alert/find", + "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", + "app:observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + "read": Array [ + "login:", + "api:slo_read", + "api:rac", + "app:slo", + "app:kibana", + "ui:catalogue/slo", + "ui:catalogue/observability", + "ui:navLinks/slo", + "ui:navLinks/kibana", + "saved_object:slo/bulk_get", + "saved_object:slo/get", + "saved_object:slo/find", + "saved_object:slo/open_point_in_time", + "saved_object:slo/close_point_in_time", + "saved_object:slo-settings/bulk_get", + "saved_object:slo-settings/get", + "saved_object:slo-settings/find", + "saved_object:slo-settings/open_point_in_time", + "saved_object:slo-settings/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:slo/read", + "alerting:slo.rules.burnRate/slo/rule/get", + "alerting:slo.rules.burnRate/slo/rule/getRuleState", + "alerting:slo.rules.burnRate/slo/rule/getAlertSummary", + "alerting:slo.rules.burnRate/slo/rule/getExecutionLog", + "alerting:slo.rules.burnRate/slo/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/slo/rule/find", + "alerting:slo.rules.burnRate/slo/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/slo/rule/getBackfill", + "alerting:slo.rules.burnRate/slo/rule/findBackfill", + "alerting:slo.rules.burnRate/slo/alert/get", + "alerting:slo.rules.burnRate/slo/alert/find", + "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", + "app:observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + }, + "uptime": Object { + "all": Array [ + "login:", + "api:uptime-read", + "api:uptime-write", + "api:lists-all", + "api:rac", + "app:uptime", + "app:kibana", + "app:synthetics", + "ui:catalogue/uptime", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/uptime", + "ui:navLinks/kibana", + "ui:navLinks/synthetics", + "saved_object:synthetics-dynamic-settings/bulk_get", + "saved_object:synthetics-dynamic-settings/get", + "saved_object:synthetics-dynamic-settings/find", + "saved_object:synthetics-dynamic-settings/open_point_in_time", + "saved_object:synthetics-dynamic-settings/close_point_in_time", + "saved_object:synthetics-dynamic-settings/create", + "saved_object:synthetics-dynamic-settings/bulk_create", + "saved_object:synthetics-dynamic-settings/update", + "saved_object:synthetics-dynamic-settings/bulk_update", + "saved_object:synthetics-dynamic-settings/delete", + "saved_object:synthetics-dynamic-settings/bulk_delete", + "saved_object:synthetics-dynamic-settings/share_to_space", + "saved_object:synthetics-monitor/bulk_get", + "saved_object:synthetics-monitor/get", + "saved_object:synthetics-monitor/find", + "saved_object:synthetics-monitor/open_point_in_time", + "saved_object:synthetics-monitor/close_point_in_time", + "saved_object:synthetics-monitor/create", + "saved_object:synthetics-monitor/bulk_create", + "saved_object:synthetics-monitor/update", + "saved_object:synthetics-monitor/bulk_update", + "saved_object:synthetics-monitor/delete", + "saved_object:synthetics-monitor/bulk_delete", + "saved_object:synthetics-monitor/share_to_space", + "saved_object:uptime-synthetics-api-key/bulk_get", + "saved_object:uptime-synthetics-api-key/get", + "saved_object:uptime-synthetics-api-key/find", + "saved_object:uptime-synthetics-api-key/open_point_in_time", + "saved_object:uptime-synthetics-api-key/close_point_in_time", + "saved_object:uptime-synthetics-api-key/create", + "saved_object:uptime-synthetics-api-key/bulk_create", + "saved_object:uptime-synthetics-api-key/update", + "saved_object:uptime-synthetics-api-key/bulk_update", + "saved_object:uptime-synthetics-api-key/delete", + "saved_object:uptime-synthetics-api-key/bulk_delete", + "saved_object:uptime-synthetics-api-key/share_to_space", + "saved_object:synthetics-privates-locations/bulk_get", + "saved_object:synthetics-privates-locations/get", + "saved_object:synthetics-privates-locations/find", + "saved_object:synthetics-privates-locations/open_point_in_time", + "saved_object:synthetics-privates-locations/close_point_in_time", + "saved_object:synthetics-privates-locations/create", + "saved_object:synthetics-privates-locations/bulk_create", + "saved_object:synthetics-privates-locations/update", + "saved_object:synthetics-privates-locations/bulk_update", + "saved_object:synthetics-privates-locations/delete", + "saved_object:synthetics-privates-locations/bulk_delete", + "saved_object:synthetics-privates-locations/share_to_space", + "saved_object:synthetics-param/bulk_get", + "saved_object:synthetics-param/get", + "saved_object:synthetics-param/find", + "saved_object:synthetics-param/open_point_in_time", + "saved_object:synthetics-param/close_point_in_time", + "saved_object:synthetics-param/create", + "saved_object:synthetics-param/bulk_create", + "saved_object:synthetics-param/update", + "saved_object:synthetics-param/bulk_update", + "saved_object:synthetics-param/delete", + "saved_object:synthetics-param/bulk_delete", + "saved_object:synthetics-param/share_to_space", + "saved_object:uptime-dynamic-settings/bulk_get", + "saved_object:uptime-dynamic-settings/get", + "saved_object:uptime-dynamic-settings/find", + "saved_object:uptime-dynamic-settings/open_point_in_time", + "saved_object:uptime-dynamic-settings/close_point_in_time", + "saved_object:uptime-dynamic-settings/create", + "saved_object:uptime-dynamic-settings/bulk_create", + "saved_object:uptime-dynamic-settings/update", + "saved_object:uptime-dynamic-settings/bulk_update", + "saved_object:uptime-dynamic-settings/delete", + "saved_object:uptime-dynamic-settings/bulk_delete", + "saved_object:uptime-dynamic-settings/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:uptime/save", + "ui:uptime/configureSettings", + "ui:uptime/show", + "ui:uptime/alerting:save", + "ui:uptime/elasticManagedLocationsEnabled", + "alerting:xpack.uptime.alerts.tls/uptime/rule/get", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/uptime/rule/find", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/rule/create", + "alerting:xpack.uptime.alerts.tls/uptime/rule/delete", + "alerting:xpack.uptime.alerts.tls/uptime/rule/update", + "alerting:xpack.uptime.alerts.tls/uptime/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/uptime/rule/enable", + "alerting:xpack.uptime.alerts.tls/uptime/rule/disable", + "alerting:xpack.uptime.alerts.tls/uptime/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/uptime/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/uptime/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/uptime/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/uptime/rule/snooze", + "alerting:xpack.uptime.alerts.tls/uptime/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/uptime/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/uptime/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/uptime/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/uptime/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/uptime/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/uptime/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/find", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/create", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/delete", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/update", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/enable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/disable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/alert/get", + "alerting:xpack.uptime.alerts.tls/uptime/alert/find", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/uptime/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/update", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "elastic_managed_locations_enabled": Array [ + "login:", + "ui:uptime/elasticManagedLocationsEnabled", + ], + "minimal_all": Array [ + "login:", + "api:uptime-read", + "api:uptime-write", + "api:lists-all", + "api:rac", + "app:uptime", + "app:kibana", + "app:synthetics", + "ui:catalogue/uptime", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/uptime", + "ui:navLinks/kibana", + "ui:navLinks/synthetics", + "saved_object:synthetics-dynamic-settings/bulk_get", + "saved_object:synthetics-dynamic-settings/get", + "saved_object:synthetics-dynamic-settings/find", + "saved_object:synthetics-dynamic-settings/open_point_in_time", + "saved_object:synthetics-dynamic-settings/close_point_in_time", + "saved_object:synthetics-dynamic-settings/create", + "saved_object:synthetics-dynamic-settings/bulk_create", + "saved_object:synthetics-dynamic-settings/update", + "saved_object:synthetics-dynamic-settings/bulk_update", + "saved_object:synthetics-dynamic-settings/delete", + "saved_object:synthetics-dynamic-settings/bulk_delete", + "saved_object:synthetics-dynamic-settings/share_to_space", + "saved_object:synthetics-monitor/bulk_get", + "saved_object:synthetics-monitor/get", + "saved_object:synthetics-monitor/find", + "saved_object:synthetics-monitor/open_point_in_time", + "saved_object:synthetics-monitor/close_point_in_time", + "saved_object:synthetics-monitor/create", + "saved_object:synthetics-monitor/bulk_create", + "saved_object:synthetics-monitor/update", + "saved_object:synthetics-monitor/bulk_update", + "saved_object:synthetics-monitor/delete", + "saved_object:synthetics-monitor/bulk_delete", + "saved_object:synthetics-monitor/share_to_space", + "saved_object:uptime-synthetics-api-key/bulk_get", + "saved_object:uptime-synthetics-api-key/get", + "saved_object:uptime-synthetics-api-key/find", + "saved_object:uptime-synthetics-api-key/open_point_in_time", + "saved_object:uptime-synthetics-api-key/close_point_in_time", + "saved_object:uptime-synthetics-api-key/create", + "saved_object:uptime-synthetics-api-key/bulk_create", + "saved_object:uptime-synthetics-api-key/update", + "saved_object:uptime-synthetics-api-key/bulk_update", + "saved_object:uptime-synthetics-api-key/delete", + "saved_object:uptime-synthetics-api-key/bulk_delete", + "saved_object:uptime-synthetics-api-key/share_to_space", + "saved_object:synthetics-privates-locations/bulk_get", + "saved_object:synthetics-privates-locations/get", + "saved_object:synthetics-privates-locations/find", + "saved_object:synthetics-privates-locations/open_point_in_time", + "saved_object:synthetics-privates-locations/close_point_in_time", + "saved_object:synthetics-privates-locations/create", + "saved_object:synthetics-privates-locations/bulk_create", + "saved_object:synthetics-privates-locations/update", + "saved_object:synthetics-privates-locations/bulk_update", + "saved_object:synthetics-privates-locations/delete", + "saved_object:synthetics-privates-locations/bulk_delete", + "saved_object:synthetics-privates-locations/share_to_space", + "saved_object:synthetics-param/bulk_get", + "saved_object:synthetics-param/get", + "saved_object:synthetics-param/find", + "saved_object:synthetics-param/open_point_in_time", + "saved_object:synthetics-param/close_point_in_time", + "saved_object:synthetics-param/create", + "saved_object:synthetics-param/bulk_create", + "saved_object:synthetics-param/update", + "saved_object:synthetics-param/bulk_update", + "saved_object:synthetics-param/delete", + "saved_object:synthetics-param/bulk_delete", + "saved_object:synthetics-param/share_to_space", + "saved_object:uptime-dynamic-settings/bulk_get", + "saved_object:uptime-dynamic-settings/get", + "saved_object:uptime-dynamic-settings/find", + "saved_object:uptime-dynamic-settings/open_point_in_time", + "saved_object:uptime-dynamic-settings/close_point_in_time", + "saved_object:uptime-dynamic-settings/create", + "saved_object:uptime-dynamic-settings/bulk_create", + "saved_object:uptime-dynamic-settings/update", + "saved_object:uptime-dynamic-settings/bulk_update", + "saved_object:uptime-dynamic-settings/delete", + "saved_object:uptime-dynamic-settings/bulk_delete", + "saved_object:uptime-dynamic-settings/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:uptime/save", + "ui:uptime/configureSettings", + "ui:uptime/show", + "ui:uptime/alerting:save", + "alerting:xpack.uptime.alerts.tls/uptime/rule/get", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/uptime/rule/find", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/rule/create", + "alerting:xpack.uptime.alerts.tls/uptime/rule/delete", + "alerting:xpack.uptime.alerts.tls/uptime/rule/update", + "alerting:xpack.uptime.alerts.tls/uptime/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/uptime/rule/enable", + "alerting:xpack.uptime.alerts.tls/uptime/rule/disable", + "alerting:xpack.uptime.alerts.tls/uptime/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/uptime/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/uptime/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/uptime/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/uptime/rule/snooze", + "alerting:xpack.uptime.alerts.tls/uptime/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/uptime/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/uptime/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/uptime/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/uptime/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/uptime/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/uptime/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/find", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/create", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/delete", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/update", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/enable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/disable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/alert/get", + "alerting:xpack.uptime.alerts.tls/uptime/alert/find", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/uptime/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/update", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/create", + "alerting:apm.error_rate/observability/rule/delete", + "alerting:apm.error_rate/observability/rule/update", + "alerting:apm.error_rate/observability/rule/updateApiKey", + "alerting:apm.error_rate/observability/rule/enable", + "alerting:apm.error_rate/observability/rule/disable", + "alerting:apm.error_rate/observability/rule/muteAll", + "alerting:apm.error_rate/observability/rule/unmuteAll", + "alerting:apm.error_rate/observability/rule/muteAlert", + "alerting:apm.error_rate/observability/rule/unmuteAlert", + "alerting:apm.error_rate/observability/rule/snooze", + "alerting:apm.error_rate/observability/rule/bulkEdit", + "alerting:apm.error_rate/observability/rule/bulkDelete", + "alerting:apm.error_rate/observability/rule/bulkEnable", + "alerting:apm.error_rate/observability/rule/bulkDisable", + "alerting:apm.error_rate/observability/rule/unsnooze", + "alerting:apm.error_rate/observability/rule/runSoon", + "alerting:apm.error_rate/observability/rule/scheduleBackfill", + "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/create", + "alerting:apm.transaction_error_rate/observability/rule/delete", + "alerting:apm.transaction_error_rate/observability/rule/update", + "alerting:apm.transaction_error_rate/observability/rule/updateApiKey", + "alerting:apm.transaction_error_rate/observability/rule/enable", + "alerting:apm.transaction_error_rate/observability/rule/disable", + "alerting:apm.transaction_error_rate/observability/rule/muteAll", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAll", + "alerting:apm.transaction_error_rate/observability/rule/muteAlert", + "alerting:apm.transaction_error_rate/observability/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/observability/rule/snooze", + "alerting:apm.transaction_error_rate/observability/rule/bulkEdit", + "alerting:apm.transaction_error_rate/observability/rule/bulkDelete", + "alerting:apm.transaction_error_rate/observability/rule/bulkEnable", + "alerting:apm.transaction_error_rate/observability/rule/bulkDisable", + "alerting:apm.transaction_error_rate/observability/rule/unsnooze", + "alerting:apm.transaction_error_rate/observability/rule/runSoon", + "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/create", + "alerting:apm.transaction_duration/observability/rule/delete", + "alerting:apm.transaction_duration/observability/rule/update", + "alerting:apm.transaction_duration/observability/rule/updateApiKey", + "alerting:apm.transaction_duration/observability/rule/enable", + "alerting:apm.transaction_duration/observability/rule/disable", + "alerting:apm.transaction_duration/observability/rule/muteAll", + "alerting:apm.transaction_duration/observability/rule/unmuteAll", + "alerting:apm.transaction_duration/observability/rule/muteAlert", + "alerting:apm.transaction_duration/observability/rule/unmuteAlert", + "alerting:apm.transaction_duration/observability/rule/snooze", + "alerting:apm.transaction_duration/observability/rule/bulkEdit", + "alerting:apm.transaction_duration/observability/rule/bulkDelete", + "alerting:apm.transaction_duration/observability/rule/bulkEnable", + "alerting:apm.transaction_duration/observability/rule/bulkDisable", + "alerting:apm.transaction_duration/observability/rule/unsnooze", + "alerting:apm.transaction_duration/observability/rule/runSoon", + "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", + "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/create", + "alerting:apm.anomaly/observability/rule/delete", + "alerting:apm.anomaly/observability/rule/update", + "alerting:apm.anomaly/observability/rule/updateApiKey", + "alerting:apm.anomaly/observability/rule/enable", + "alerting:apm.anomaly/observability/rule/disable", + "alerting:apm.anomaly/observability/rule/muteAll", + "alerting:apm.anomaly/observability/rule/unmuteAll", + "alerting:apm.anomaly/observability/rule/muteAlert", + "alerting:apm.anomaly/observability/rule/unmuteAlert", + "alerting:apm.anomaly/observability/rule/snooze", + "alerting:apm.anomaly/observability/rule/bulkEdit", + "alerting:apm.anomaly/observability/rule/bulkDelete", + "alerting:apm.anomaly/observability/rule/bulkEnable", + "alerting:apm.anomaly/observability/rule/bulkDisable", + "alerting:apm.anomaly/observability/rule/unsnooze", + "alerting:apm.anomaly/observability/rule/runSoon", + "alerting:apm.anomaly/observability/rule/scheduleBackfill", + "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + ], + "minimal_read": Array [ + "login:", + "api:uptime-read", + "api:lists-read", + "api:rac", + "app:uptime", + "app:kibana", + "app:synthetics", + "ui:catalogue/uptime", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/uptime", + "ui:navLinks/kibana", + "ui:navLinks/synthetics", + "saved_object:synthetics-param/bulk_get", + "saved_object:synthetics-param/get", + "saved_object:synthetics-param/find", + "saved_object:synthetics-param/open_point_in_time", + "saved_object:synthetics-param/close_point_in_time", + "saved_object:synthetics-dynamic-settings/bulk_get", + "saved_object:synthetics-dynamic-settings/get", + "saved_object:synthetics-dynamic-settings/find", + "saved_object:synthetics-dynamic-settings/open_point_in_time", + "saved_object:synthetics-dynamic-settings/close_point_in_time", + "saved_object:synthetics-monitor/bulk_get", + "saved_object:synthetics-monitor/get", + "saved_object:synthetics-monitor/find", + "saved_object:synthetics-monitor/open_point_in_time", + "saved_object:synthetics-monitor/close_point_in_time", + "saved_object:uptime-synthetics-api-key/bulk_get", + "saved_object:uptime-synthetics-api-key/get", + "saved_object:uptime-synthetics-api-key/find", + "saved_object:uptime-synthetics-api-key/open_point_in_time", + "saved_object:uptime-synthetics-api-key/close_point_in_time", + "saved_object:synthetics-privates-locations/bulk_get", + "saved_object:synthetics-privates-locations/get", + "saved_object:synthetics-privates-locations/find", + "saved_object:synthetics-privates-locations/open_point_in_time", + "saved_object:synthetics-privates-locations/close_point_in_time", + "saved_object:uptime-dynamic-settings/bulk_get", + "saved_object:uptime-dynamic-settings/get", + "saved_object:uptime-dynamic-settings/find", + "saved_object:uptime-dynamic-settings/open_point_in_time", + "saved_object:uptime-dynamic-settings/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:uptime/show", + "ui:uptime/alerting:save", + "alerting:xpack.uptime.alerts.tls/uptime/rule/get", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/uptime/rule/find", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/find", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/alert/get", + "alerting:xpack.uptime.alerts.tls/uptime/alert/find", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + "read": Array [ + "login:", + "api:uptime-read", + "api:lists-read", + "api:rac", + "app:uptime", + "app:kibana", + "app:synthetics", + "ui:catalogue/uptime", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/uptime", + "ui:navLinks/kibana", + "ui:navLinks/synthetics", + "saved_object:synthetics-param/bulk_get", + "saved_object:synthetics-param/get", + "saved_object:synthetics-param/find", + "saved_object:synthetics-param/open_point_in_time", + "saved_object:synthetics-param/close_point_in_time", + "saved_object:synthetics-dynamic-settings/bulk_get", + "saved_object:synthetics-dynamic-settings/get", + "saved_object:synthetics-dynamic-settings/find", + "saved_object:synthetics-dynamic-settings/open_point_in_time", + "saved_object:synthetics-dynamic-settings/close_point_in_time", + "saved_object:synthetics-monitor/bulk_get", + "saved_object:synthetics-monitor/get", + "saved_object:synthetics-monitor/find", + "saved_object:synthetics-monitor/open_point_in_time", + "saved_object:synthetics-monitor/close_point_in_time", + "saved_object:uptime-synthetics-api-key/bulk_get", + "saved_object:uptime-synthetics-api-key/get", + "saved_object:uptime-synthetics-api-key/find", + "saved_object:uptime-synthetics-api-key/open_point_in_time", + "saved_object:uptime-synthetics-api-key/close_point_in_time", + "saved_object:synthetics-privates-locations/bulk_get", + "saved_object:synthetics-privates-locations/get", + "saved_object:synthetics-privates-locations/find", + "saved_object:synthetics-privates-locations/open_point_in_time", + "saved_object:synthetics-privates-locations/close_point_in_time", + "saved_object:uptime-dynamic-settings/bulk_get", + "saved_object:uptime-dynamic-settings/get", + "saved_object:uptime-dynamic-settings/find", + "saved_object:uptime-dynamic-settings/open_point_in_time", + "saved_object:uptime-dynamic-settings/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:uptime/show", + "ui:uptime/alerting:save", + "alerting:xpack.uptime.alerts.tls/uptime/rule/get", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/uptime/rule/find", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/find", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/alert/get", + "alerting:xpack.uptime.alerts.tls/uptime/alert/find", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:apm.error_rate/observability/rule/get", + "alerting:apm.error_rate/observability/rule/getRuleState", + "alerting:apm.error_rate/observability/rule/getAlertSummary", + "alerting:apm.error_rate/observability/rule/getExecutionLog", + "alerting:apm.error_rate/observability/rule/getActionErrorLog", + "alerting:apm.error_rate/observability/rule/find", + "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/observability/rule/getBackfill", + "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/observability/rule/get", + "alerting:apm.transaction_error_rate/observability/rule/getRuleState", + "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/observability/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/observability/rule/find", + "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/observability/rule/getBackfill", + "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_duration/observability/rule/get", + "alerting:apm.transaction_duration/observability/rule/getRuleState", + "alerting:apm.transaction_duration/observability/rule/getAlertSummary", + "alerting:apm.transaction_duration/observability/rule/getExecutionLog", + "alerting:apm.transaction_duration/observability/rule/getActionErrorLog", + "alerting:apm.transaction_duration/observability/rule/find", + "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/observability/rule/getBackfill", + "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.anomaly/observability/rule/get", + "alerting:apm.anomaly/observability/rule/getRuleState", + "alerting:apm.anomaly/observability/rule/getAlertSummary", + "alerting:apm.anomaly/observability/rule/getExecutionLog", + "alerting:apm.anomaly/observability/rule/getActionErrorLog", + "alerting:apm.anomaly/observability/rule/find", + "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/observability/rule/getBackfill", + "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + ], + }, + } + `); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/index.ts b/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/index.ts new file mode 100644 index 0000000000000..5271f15b683f1 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/index.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. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Platform security APIs', function () { + loadTestFile(require.resolve('./authorization')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts index 90009b3b57ded..a757df76f10f3 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts @@ -9,6 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Serverless search API - feature flags', function () { + loadTestFile(require.resolve('./platform_security')); loadTestFile(require.resolve('../common/platform_security/roles_routes_feature_flag.ts')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/search/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/search/platform_security/authorization.ts new file mode 100644 index 0000000000000..b05dd338c64ac --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/search/platform_security/authorization.ts @@ -0,0 +1,1029 @@ +/* + * 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 { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const svlCommonApi = getService('svlCommonApi'); + + describe('security/authorization', function () { + describe('available features', () => { + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + let adminCredentials: { Cookie: string }; + + before(async () => { + // get auth header for Viewer role + adminCredentials = await svlUserManager.getApiCredentialsForRole('admin'); + }); + + it('composite features', async () => { + const { body } = await supertestWithoutAuth + .get('/api/security/privileges?includeActions=true') + .set(svlCommonApi.getInternalRequestHeader()) + .set(adminCredentials) + .expect(200); + + // The following features are composed of other features in a way that is + // specific to the search solution. + const compositeFeatureIds = ['dashboard', 'discover', 'reporting']; + + const features = Object.fromEntries( + Object.entries(body.features).filter(([key]) => compositeFeatureIds.includes(key)) + ); + expectSnapshot(features).toMatchInline(` + Object { + "dashboard": Object { + "all": Array [ + "login:", + "api:bulkGetUserProfiles", + "api:store_search_session", + "api:generateReport", + "api:downloadCsv", + "app:dashboards", + "app:kibana", + "ui:catalogue/dashboard", + "ui:management/kibana/search_sessions", + "ui:management/insightsAndAlerting/reporting", + "ui:navLinks/dashboards", + "ui:navLinks/kibana", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:dashboard/create", + "saved_object:dashboard/bulk_create", + "saved_object:dashboard/update", + "saved_object:dashboard/bulk_update", + "saved_object:dashboard/delete", + "saved_object:dashboard/bulk_delete", + "saved_object:dashboard/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "ui:dashboard/createNew", + "ui:dashboard/show", + "ui:dashboard/showWriteControls", + "ui:dashboard/saveQuery", + "ui:dashboard/createShortUrl", + "ui:dashboard/storeSearchSession", + "ui:dashboard/generateScreenshot", + "ui:dashboard/downloadCsv", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "saved_object:map/create", + "saved_object:map/bulk_create", + "saved_object:map/update", + "saved_object:map/bulk_update", + "saved_object:map/delete", + "saved_object:map/bulk_delete", + "saved_object:map/share_to_space", + "ui:maps/save", + "ui:maps/show", + "ui:maps/saveQuery", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "saved_object:visualization/create", + "saved_object:visualization/bulk_create", + "saved_object:visualization/update", + "saved_object:visualization/bulk_update", + "saved_object:visualization/delete", + "saved_object:visualization/bulk_delete", + "saved_object:visualization/share_to_space", + "saved_object:lens/create", + "saved_object:lens/bulk_create", + "saved_object:lens/update", + "saved_object:lens/bulk_update", + "saved_object:lens/delete", + "saved_object:lens/bulk_delete", + "saved_object:lens/share_to_space", + "ui:visualize/show", + "ui:visualize/delete", + "ui:visualize/save", + "ui:visualize/saveQuery", + "ui:visualize/createShortUrl", + "ui:visualize/generateScreenshot", + ], + "download_csv_report": Array [ + "login:", + "api:downloadCsv", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/downloadCsv", + ], + "generate_report": Array [ + "login:", + "api:generateReport", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/generateScreenshot", + ], + "minimal_all": Array [ + "login:", + "api:bulkGetUserProfiles", + "app:dashboards", + "app:kibana", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "ui:navLinks/kibana", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:dashboard/create", + "saved_object:dashboard/bulk_create", + "saved_object:dashboard/update", + "saved_object:dashboard/bulk_update", + "saved_object:dashboard/delete", + "saved_object:dashboard/bulk_delete", + "saved_object:dashboard/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:dashboard/createNew", + "ui:dashboard/show", + "ui:dashboard/showWriteControls", + "ui:dashboard/saveQuery", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "saved_object:map/create", + "saved_object:map/bulk_create", + "saved_object:map/update", + "saved_object:map/bulk_update", + "saved_object:map/delete", + "saved_object:map/bulk_delete", + "saved_object:map/share_to_space", + "ui:maps/save", + "ui:maps/show", + "ui:maps/saveQuery", + "api:generateReport", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:management/insightsAndAlerting/reporting", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "saved_object:visualization/create", + "saved_object:visualization/bulk_create", + "saved_object:visualization/update", + "saved_object:visualization/bulk_update", + "saved_object:visualization/delete", + "saved_object:visualization/bulk_delete", + "saved_object:visualization/share_to_space", + "saved_object:lens/create", + "saved_object:lens/bulk_create", + "saved_object:lens/update", + "saved_object:lens/bulk_update", + "saved_object:lens/delete", + "saved_object:lens/bulk_delete", + "saved_object:lens/share_to_space", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "ui:visualize/show", + "ui:visualize/delete", + "ui:visualize/save", + "ui:visualize/saveQuery", + "ui:visualize/createShortUrl", + "ui:visualize/generateScreenshot", + ], + "minimal_read": Array [ + "login:", + "api:bulkGetUserProfiles", + "app:dashboards", + "app:kibana", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "ui:navLinks/kibana", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:dashboard/show", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "ui:maps/show", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "ui:visualize/show", + "ui:visualize/createShortUrl", + ], + "read": Array [ + "login:", + "api:bulkGetUserProfiles", + "app:dashboards", + "app:kibana", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "ui:navLinks/kibana", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "ui:dashboard/show", + "ui:dashboard/createShortUrl", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "ui:maps/show", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "ui:visualize/show", + "ui:visualize/createShortUrl", + ], + "store_search_session": Array [ + "login:", + "api:store_search_session", + "ui:management/kibana/search_sessions", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "ui:dashboard/storeSearchSession", + ], + "url_create": Array [ + "login:", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "ui:dashboard/createShortUrl", + ], + }, + "discover": Object { + "all": Array [ + "login:", + "api:fileUpload:analyzeFile", + "api:store_search_session", + "api:generateReport", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:management/kibana/search_sessions", + "ui:management/insightsAndAlerting/reporting", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:search/create", + "saved_object:search/bulk_create", + "saved_object:search/update", + "saved_object:search/bulk_update", + "saved_object:search/delete", + "saved_object:search/bulk_delete", + "saved_object:search/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "ui:discover/show", + "ui:discover/save", + "ui:discover/saveQuery", + "ui:discover/createShortUrl", + "ui:discover/storeSearchSession", + "ui:discover/generateCsv", + ], + "generate_report": Array [ + "login:", + "api:generateReport", + "ui:management/insightsAndAlerting/reporting", + "ui:discover/generateCsv", + ], + "minimal_all": Array [ + "login:", + "api:fileUpload:analyzeFile", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:search/create", + "saved_object:search/bulk_create", + "saved_object:search/update", + "saved_object:search/bulk_update", + "saved_object:search/delete", + "saved_object:search/bulk_delete", + "saved_object:search/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:discover/show", + "ui:discover/save", + "ui:discover/saveQuery", + ], + "minimal_read": Array [ + "login:", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:discover/show", + ], + "read": Array [ + "login:", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "ui:discover/show", + "ui:discover/createShortUrl", + ], + "store_search_session": Array [ + "login:", + "api:store_search_session", + "ui:management/kibana/search_sessions", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "ui:discover/storeSearchSession", + ], + "url_create": Array [ + "login:", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "ui:discover/createShortUrl", + ], + }, + "reporting": Object { + "all": Array [ + "login:", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "api:downloadCsv", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/downloadCsv", + "api:generateReport", + "ui:discover/generateCsv", + ], + "minimal_all": Array [ + "login:", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "api:downloadCsv", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/downloadCsv", + "api:generateReport", + "ui:discover/generateCsv", + ], + "minimal_read": Array [ + "login:", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + ], + "read": Array [ + "login:", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + ], + }, + } + `); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/search/platform_security/index.ts b/x-pack/test_serverless/api_integration/test_suites/search/platform_security/index.ts new file mode 100644 index 0000000000000..5271f15b683f1 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/search/platform_security/index.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. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Platform security APIs', function () { + loadTestFile(require.resolve('./authorization')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/security/index.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/security/index.feature_flags.ts index e3f61f3dde03c..f929d3e64c6bc 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/index.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/index.feature_flags.ts @@ -9,6 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Serverless security API - feature flags', function () { + loadTestFile(require.resolve('./platform_security')); loadTestFile(require.resolve('../common/platform_security/roles_routes_feature_flag.ts')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/security/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/security/platform_security/authorization.ts new file mode 100644 index 0000000000000..54e9f5c1cbdf5 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/security/platform_security/authorization.ts @@ -0,0 +1,2412 @@ +/* + * 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 { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const svlCommonApi = getService('svlCommonApi'); + + describe('security/authorization', function () { + describe('available features', () => { + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + let adminCredentials: { Cookie: string }; + + before(async () => { + // get auth header for Viewer role + adminCredentials = await svlUserManager.getApiCredentialsForRole('admin'); + }); + + it('composite features', async () => { + const { body } = await supertestWithoutAuth + .get('/api/security/privileges?includeActions=true') + .set(svlCommonApi.getInternalRequestHeader()) + .set(adminCredentials) + .expect(200); + + // The following features are composed of other features in a way that is + // specific to the security solution. + const compositeFeatureIds = ['dashboard', 'discover', 'reporting', 'siem']; + + const features = Object.fromEntries( + Object.entries(body.features).filter(([key]) => compositeFeatureIds.includes(key)) + ); + expectSnapshot(features).toMatchInline(` + Object { + "reporting": Object { + "all": Array [ + "login:", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "api:downloadCsv", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/downloadCsv", + "api:generateReport", + "ui:discover/generateCsv", + ], + "minimal_all": Array [ + "login:", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "api:downloadCsv", + "ui:management/insightsAndAlerting/reporting", + "ui:dashboard/downloadCsv", + "api:generateReport", + "ui:discover/generateCsv", + ], + "minimal_read": Array [ + "login:", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + ], + "read": Array [ + "login:", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + ], + }, + "siem": Object { + "actions_log_management_all": Array [ + "login:", + "api:securitySolution-writeActionsLogManagement", + "api:securitySolution-readActionsLogManagement", + "ui:siem/writeActionsLogManagement", + "ui:siem/readActionsLogManagement", + ], + "actions_log_management_read": Array [ + "login:", + "api:securitySolution-readActionsLogManagement", + "ui:siem/readActionsLogManagement", + ], + "all": Array [ + "login:", + "api:securitySolution", + "api:lists-all", + "api:lists-read", + "api:lists-summary", + "api:rac", + "api:cloud-security-posture-all", + "api:cloud-security-posture-read", + "api:cloud-defend-all", + "api:cloud-defend-read", + "api:securitySolution-entity-analytics", + "api:securitySolution-threat-intelligence", + "api:securitySolution-showEndpointExceptions", + "api:securitySolution-crudEndpointExceptions", + "app:securitySolution", + "app:csp", + "app:cloudDefend", + "app:kibana", + "ui:catalogue/securitySolution", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/securitySolution", + "ui:navLinks/csp", + "ui:navLinks/cloudDefend", + "ui:navLinks/kibana", + "saved_object:alert/bulk_get", + "saved_object:alert/get", + "saved_object:alert/find", + "saved_object:alert/open_point_in_time", + "saved_object:alert/close_point_in_time", + "saved_object:alert/create", + "saved_object:alert/bulk_create", + "saved_object:alert/update", + "saved_object:alert/bulk_update", + "saved_object:alert/delete", + "saved_object:alert/bulk_delete", + "saved_object:alert/share_to_space", + "saved_object:exception-list/bulk_get", + "saved_object:exception-list/get", + "saved_object:exception-list/find", + "saved_object:exception-list/open_point_in_time", + "saved_object:exception-list/close_point_in_time", + "saved_object:exception-list/create", + "saved_object:exception-list/bulk_create", + "saved_object:exception-list/update", + "saved_object:exception-list/bulk_update", + "saved_object:exception-list/delete", + "saved_object:exception-list/bulk_delete", + "saved_object:exception-list/share_to_space", + "saved_object:exception-list-agnostic/bulk_get", + "saved_object:exception-list-agnostic/get", + "saved_object:exception-list-agnostic/find", + "saved_object:exception-list-agnostic/open_point_in_time", + "saved_object:exception-list-agnostic/close_point_in_time", + "saved_object:exception-list-agnostic/create", + "saved_object:exception-list-agnostic/bulk_create", + "saved_object:exception-list-agnostic/update", + "saved_object:exception-list-agnostic/bulk_update", + "saved_object:exception-list-agnostic/delete", + "saved_object:exception-list-agnostic/bulk_delete", + "saved_object:exception-list-agnostic/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:index-pattern/create", + "saved_object:index-pattern/bulk_create", + "saved_object:index-pattern/update", + "saved_object:index-pattern/bulk_update", + "saved_object:index-pattern/delete", + "saved_object:index-pattern/bulk_delete", + "saved_object:index-pattern/share_to_space", + "saved_object:siem-ui-timeline-note/bulk_get", + "saved_object:siem-ui-timeline-note/get", + "saved_object:siem-ui-timeline-note/find", + "saved_object:siem-ui-timeline-note/open_point_in_time", + "saved_object:siem-ui-timeline-note/close_point_in_time", + "saved_object:siem-ui-timeline-note/create", + "saved_object:siem-ui-timeline-note/bulk_create", + "saved_object:siem-ui-timeline-note/update", + "saved_object:siem-ui-timeline-note/bulk_update", + "saved_object:siem-ui-timeline-note/delete", + "saved_object:siem-ui-timeline-note/bulk_delete", + "saved_object:siem-ui-timeline-note/share_to_space", + "saved_object:siem-ui-timeline-pinned-event/bulk_get", + "saved_object:siem-ui-timeline-pinned-event/get", + "saved_object:siem-ui-timeline-pinned-event/find", + "saved_object:siem-ui-timeline-pinned-event/open_point_in_time", + "saved_object:siem-ui-timeline-pinned-event/close_point_in_time", + "saved_object:siem-ui-timeline-pinned-event/create", + "saved_object:siem-ui-timeline-pinned-event/bulk_create", + "saved_object:siem-ui-timeline-pinned-event/update", + "saved_object:siem-ui-timeline-pinned-event/bulk_update", + "saved_object:siem-ui-timeline-pinned-event/delete", + "saved_object:siem-ui-timeline-pinned-event/bulk_delete", + "saved_object:siem-ui-timeline-pinned-event/share_to_space", + "saved_object:siem-detection-engine-rule-actions/bulk_get", + "saved_object:siem-detection-engine-rule-actions/get", + "saved_object:siem-detection-engine-rule-actions/find", + "saved_object:siem-detection-engine-rule-actions/open_point_in_time", + "saved_object:siem-detection-engine-rule-actions/close_point_in_time", + "saved_object:siem-detection-engine-rule-actions/create", + "saved_object:siem-detection-engine-rule-actions/bulk_create", + "saved_object:siem-detection-engine-rule-actions/update", + "saved_object:siem-detection-engine-rule-actions/bulk_update", + "saved_object:siem-detection-engine-rule-actions/delete", + "saved_object:siem-detection-engine-rule-actions/bulk_delete", + "saved_object:siem-detection-engine-rule-actions/share_to_space", + "saved_object:security-rule/bulk_get", + "saved_object:security-rule/get", + "saved_object:security-rule/find", + "saved_object:security-rule/open_point_in_time", + "saved_object:security-rule/close_point_in_time", + "saved_object:security-rule/create", + "saved_object:security-rule/bulk_create", + "saved_object:security-rule/update", + "saved_object:security-rule/bulk_update", + "saved_object:security-rule/delete", + "saved_object:security-rule/bulk_delete", + "saved_object:security-rule/share_to_space", + "saved_object:siem-ui-timeline/bulk_get", + "saved_object:siem-ui-timeline/get", + "saved_object:siem-ui-timeline/find", + "saved_object:siem-ui-timeline/open_point_in_time", + "saved_object:siem-ui-timeline/close_point_in_time", + "saved_object:siem-ui-timeline/create", + "saved_object:siem-ui-timeline/bulk_create", + "saved_object:siem-ui-timeline/update", + "saved_object:siem-ui-timeline/bulk_update", + "saved_object:siem-ui-timeline/delete", + "saved_object:siem-ui-timeline/bulk_delete", + "saved_object:siem-ui-timeline/share_to_space", + "saved_object:endpoint:user-artifact-manifest/bulk_get", + "saved_object:endpoint:user-artifact-manifest/get", + "saved_object:endpoint:user-artifact-manifest/find", + "saved_object:endpoint:user-artifact-manifest/open_point_in_time", + "saved_object:endpoint:user-artifact-manifest/close_point_in_time", + "saved_object:endpoint:user-artifact-manifest/create", + "saved_object:endpoint:user-artifact-manifest/bulk_create", + "saved_object:endpoint:user-artifact-manifest/update", + "saved_object:endpoint:user-artifact-manifest/bulk_update", + "saved_object:endpoint:user-artifact-manifest/delete", + "saved_object:endpoint:user-artifact-manifest/bulk_delete", + "saved_object:endpoint:user-artifact-manifest/share_to_space", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_get", + "saved_object:endpoint:unified-user-artifact-manifest/get", + "saved_object:endpoint:unified-user-artifact-manifest/find", + "saved_object:endpoint:unified-user-artifact-manifest/open_point_in_time", + "saved_object:endpoint:unified-user-artifact-manifest/close_point_in_time", + "saved_object:endpoint:unified-user-artifact-manifest/create", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_create", + "saved_object:endpoint:unified-user-artifact-manifest/update", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_update", + "saved_object:endpoint:unified-user-artifact-manifest/delete", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_delete", + "saved_object:endpoint:unified-user-artifact-manifest/share_to_space", + "saved_object:security-solution-signals-migration/bulk_get", + "saved_object:security-solution-signals-migration/get", + "saved_object:security-solution-signals-migration/find", + "saved_object:security-solution-signals-migration/open_point_in_time", + "saved_object:security-solution-signals-migration/close_point_in_time", + "saved_object:security-solution-signals-migration/create", + "saved_object:security-solution-signals-migration/bulk_create", + "saved_object:security-solution-signals-migration/update", + "saved_object:security-solution-signals-migration/bulk_update", + "saved_object:security-solution-signals-migration/delete", + "saved_object:security-solution-signals-migration/bulk_delete", + "saved_object:security-solution-signals-migration/share_to_space", + "saved_object:risk-engine-configuration/bulk_get", + "saved_object:risk-engine-configuration/get", + "saved_object:risk-engine-configuration/find", + "saved_object:risk-engine-configuration/open_point_in_time", + "saved_object:risk-engine-configuration/close_point_in_time", + "saved_object:risk-engine-configuration/create", + "saved_object:risk-engine-configuration/bulk_create", + "saved_object:risk-engine-configuration/update", + "saved_object:risk-engine-configuration/bulk_update", + "saved_object:risk-engine-configuration/delete", + "saved_object:risk-engine-configuration/bulk_delete", + "saved_object:risk-engine-configuration/share_to_space", + "saved_object:policy-settings-protection-updates-note/bulk_get", + "saved_object:policy-settings-protection-updates-note/get", + "saved_object:policy-settings-protection-updates-note/find", + "saved_object:policy-settings-protection-updates-note/open_point_in_time", + "saved_object:policy-settings-protection-updates-note/close_point_in_time", + "saved_object:policy-settings-protection-updates-note/create", + "saved_object:policy-settings-protection-updates-note/bulk_create", + "saved_object:policy-settings-protection-updates-note/update", + "saved_object:policy-settings-protection-updates-note/bulk_update", + "saved_object:policy-settings-protection-updates-note/delete", + "saved_object:policy-settings-protection-updates-note/bulk_delete", + "saved_object:policy-settings-protection-updates-note/share_to_space", + "saved_object:csp_rule/bulk_get", + "saved_object:csp_rule/get", + "saved_object:csp_rule/find", + "saved_object:csp_rule/open_point_in_time", + "saved_object:csp_rule/close_point_in_time", + "saved_object:csp_rule/create", + "saved_object:csp_rule/bulk_create", + "saved_object:csp_rule/update", + "saved_object:csp_rule/bulk_update", + "saved_object:csp_rule/delete", + "saved_object:csp_rule/bulk_delete", + "saved_object:csp_rule/share_to_space", + "saved_object:cloud-security-posture-settings/bulk_get", + "saved_object:cloud-security-posture-settings/get", + "saved_object:cloud-security-posture-settings/find", + "saved_object:cloud-security-posture-settings/open_point_in_time", + "saved_object:cloud-security-posture-settings/close_point_in_time", + "saved_object:cloud-security-posture-settings/create", + "saved_object:cloud-security-posture-settings/bulk_create", + "saved_object:cloud-security-posture-settings/update", + "saved_object:cloud-security-posture-settings/bulk_update", + "saved_object:cloud-security-posture-settings/delete", + "saved_object:cloud-security-posture-settings/bulk_delete", + "saved_object:cloud-security-posture-settings/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:siem/show", + "ui:siem/crud", + "ui:siem/entity-analytics", + "ui:siem/investigation-guide", + "ui:siem/investigation-guide-interactions", + "ui:siem/threat-intelligence", + "ui:siem/showEndpointExceptions", + "ui:siem/crudEndpointExceptions", + "alerting:siem.notifications/siem/rule/get", + "alerting:siem.notifications/siem/rule/getRuleState", + "alerting:siem.notifications/siem/rule/getAlertSummary", + "alerting:siem.notifications/siem/rule/getExecutionLog", + "alerting:siem.notifications/siem/rule/getActionErrorLog", + "alerting:siem.notifications/siem/rule/find", + "alerting:siem.notifications/siem/rule/getRuleExecutionKPI", + "alerting:siem.notifications/siem/rule/getBackfill", + "alerting:siem.notifications/siem/rule/findBackfill", + "alerting:siem.notifications/siem/rule/create", + "alerting:siem.notifications/siem/rule/delete", + "alerting:siem.notifications/siem/rule/update", + "alerting:siem.notifications/siem/rule/updateApiKey", + "alerting:siem.notifications/siem/rule/enable", + "alerting:siem.notifications/siem/rule/disable", + "alerting:siem.notifications/siem/rule/muteAll", + "alerting:siem.notifications/siem/rule/unmuteAll", + "alerting:siem.notifications/siem/rule/muteAlert", + "alerting:siem.notifications/siem/rule/unmuteAlert", + "alerting:siem.notifications/siem/rule/snooze", + "alerting:siem.notifications/siem/rule/bulkEdit", + "alerting:siem.notifications/siem/rule/bulkDelete", + "alerting:siem.notifications/siem/rule/bulkEnable", + "alerting:siem.notifications/siem/rule/bulkDisable", + "alerting:siem.notifications/siem/rule/unsnooze", + "alerting:siem.notifications/siem/rule/runSoon", + "alerting:siem.notifications/siem/rule/scheduleBackfill", + "alerting:siem.notifications/siem/rule/deleteBackfill", + "alerting:siem.esqlRule/siem/rule/get", + "alerting:siem.esqlRule/siem/rule/getRuleState", + "alerting:siem.esqlRule/siem/rule/getAlertSummary", + "alerting:siem.esqlRule/siem/rule/getExecutionLog", + "alerting:siem.esqlRule/siem/rule/getActionErrorLog", + "alerting:siem.esqlRule/siem/rule/find", + "alerting:siem.esqlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.esqlRule/siem/rule/getBackfill", + "alerting:siem.esqlRule/siem/rule/findBackfill", + "alerting:siem.esqlRule/siem/rule/create", + "alerting:siem.esqlRule/siem/rule/delete", + "alerting:siem.esqlRule/siem/rule/update", + "alerting:siem.esqlRule/siem/rule/updateApiKey", + "alerting:siem.esqlRule/siem/rule/enable", + "alerting:siem.esqlRule/siem/rule/disable", + "alerting:siem.esqlRule/siem/rule/muteAll", + "alerting:siem.esqlRule/siem/rule/unmuteAll", + "alerting:siem.esqlRule/siem/rule/muteAlert", + "alerting:siem.esqlRule/siem/rule/unmuteAlert", + "alerting:siem.esqlRule/siem/rule/snooze", + "alerting:siem.esqlRule/siem/rule/bulkEdit", + "alerting:siem.esqlRule/siem/rule/bulkDelete", + "alerting:siem.esqlRule/siem/rule/bulkEnable", + "alerting:siem.esqlRule/siem/rule/bulkDisable", + "alerting:siem.esqlRule/siem/rule/unsnooze", + "alerting:siem.esqlRule/siem/rule/runSoon", + "alerting:siem.esqlRule/siem/rule/scheduleBackfill", + "alerting:siem.esqlRule/siem/rule/deleteBackfill", + "alerting:siem.eqlRule/siem/rule/get", + "alerting:siem.eqlRule/siem/rule/getRuleState", + "alerting:siem.eqlRule/siem/rule/getAlertSummary", + "alerting:siem.eqlRule/siem/rule/getExecutionLog", + "alerting:siem.eqlRule/siem/rule/getActionErrorLog", + "alerting:siem.eqlRule/siem/rule/find", + "alerting:siem.eqlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.eqlRule/siem/rule/getBackfill", + "alerting:siem.eqlRule/siem/rule/findBackfill", + "alerting:siem.eqlRule/siem/rule/create", + "alerting:siem.eqlRule/siem/rule/delete", + "alerting:siem.eqlRule/siem/rule/update", + "alerting:siem.eqlRule/siem/rule/updateApiKey", + "alerting:siem.eqlRule/siem/rule/enable", + "alerting:siem.eqlRule/siem/rule/disable", + "alerting:siem.eqlRule/siem/rule/muteAll", + "alerting:siem.eqlRule/siem/rule/unmuteAll", + "alerting:siem.eqlRule/siem/rule/muteAlert", + "alerting:siem.eqlRule/siem/rule/unmuteAlert", + "alerting:siem.eqlRule/siem/rule/snooze", + "alerting:siem.eqlRule/siem/rule/bulkEdit", + "alerting:siem.eqlRule/siem/rule/bulkDelete", + "alerting:siem.eqlRule/siem/rule/bulkEnable", + "alerting:siem.eqlRule/siem/rule/bulkDisable", + "alerting:siem.eqlRule/siem/rule/unsnooze", + "alerting:siem.eqlRule/siem/rule/runSoon", + "alerting:siem.eqlRule/siem/rule/scheduleBackfill", + "alerting:siem.eqlRule/siem/rule/deleteBackfill", + "alerting:siem.indicatorRule/siem/rule/get", + "alerting:siem.indicatorRule/siem/rule/getRuleState", + "alerting:siem.indicatorRule/siem/rule/getAlertSummary", + "alerting:siem.indicatorRule/siem/rule/getExecutionLog", + "alerting:siem.indicatorRule/siem/rule/getActionErrorLog", + "alerting:siem.indicatorRule/siem/rule/find", + "alerting:siem.indicatorRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.indicatorRule/siem/rule/getBackfill", + "alerting:siem.indicatorRule/siem/rule/findBackfill", + "alerting:siem.indicatorRule/siem/rule/create", + "alerting:siem.indicatorRule/siem/rule/delete", + "alerting:siem.indicatorRule/siem/rule/update", + "alerting:siem.indicatorRule/siem/rule/updateApiKey", + "alerting:siem.indicatorRule/siem/rule/enable", + "alerting:siem.indicatorRule/siem/rule/disable", + "alerting:siem.indicatorRule/siem/rule/muteAll", + "alerting:siem.indicatorRule/siem/rule/unmuteAll", + "alerting:siem.indicatorRule/siem/rule/muteAlert", + "alerting:siem.indicatorRule/siem/rule/unmuteAlert", + "alerting:siem.indicatorRule/siem/rule/snooze", + "alerting:siem.indicatorRule/siem/rule/bulkEdit", + "alerting:siem.indicatorRule/siem/rule/bulkDelete", + "alerting:siem.indicatorRule/siem/rule/bulkEnable", + "alerting:siem.indicatorRule/siem/rule/bulkDisable", + "alerting:siem.indicatorRule/siem/rule/unsnooze", + "alerting:siem.indicatorRule/siem/rule/runSoon", + "alerting:siem.indicatorRule/siem/rule/scheduleBackfill", + "alerting:siem.indicatorRule/siem/rule/deleteBackfill", + "alerting:siem.mlRule/siem/rule/get", + "alerting:siem.mlRule/siem/rule/getRuleState", + "alerting:siem.mlRule/siem/rule/getAlertSummary", + "alerting:siem.mlRule/siem/rule/getExecutionLog", + "alerting:siem.mlRule/siem/rule/getActionErrorLog", + "alerting:siem.mlRule/siem/rule/find", + "alerting:siem.mlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.mlRule/siem/rule/getBackfill", + "alerting:siem.mlRule/siem/rule/findBackfill", + "alerting:siem.mlRule/siem/rule/create", + "alerting:siem.mlRule/siem/rule/delete", + "alerting:siem.mlRule/siem/rule/update", + "alerting:siem.mlRule/siem/rule/updateApiKey", + "alerting:siem.mlRule/siem/rule/enable", + "alerting:siem.mlRule/siem/rule/disable", + "alerting:siem.mlRule/siem/rule/muteAll", + "alerting:siem.mlRule/siem/rule/unmuteAll", + "alerting:siem.mlRule/siem/rule/muteAlert", + "alerting:siem.mlRule/siem/rule/unmuteAlert", + "alerting:siem.mlRule/siem/rule/snooze", + "alerting:siem.mlRule/siem/rule/bulkEdit", + "alerting:siem.mlRule/siem/rule/bulkDelete", + "alerting:siem.mlRule/siem/rule/bulkEnable", + "alerting:siem.mlRule/siem/rule/bulkDisable", + "alerting:siem.mlRule/siem/rule/unsnooze", + "alerting:siem.mlRule/siem/rule/runSoon", + "alerting:siem.mlRule/siem/rule/scheduleBackfill", + "alerting:siem.mlRule/siem/rule/deleteBackfill", + "alerting:siem.queryRule/siem/rule/get", + "alerting:siem.queryRule/siem/rule/getRuleState", + "alerting:siem.queryRule/siem/rule/getAlertSummary", + "alerting:siem.queryRule/siem/rule/getExecutionLog", + "alerting:siem.queryRule/siem/rule/getActionErrorLog", + "alerting:siem.queryRule/siem/rule/find", + "alerting:siem.queryRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.queryRule/siem/rule/getBackfill", + "alerting:siem.queryRule/siem/rule/findBackfill", + "alerting:siem.queryRule/siem/rule/create", + "alerting:siem.queryRule/siem/rule/delete", + "alerting:siem.queryRule/siem/rule/update", + "alerting:siem.queryRule/siem/rule/updateApiKey", + "alerting:siem.queryRule/siem/rule/enable", + "alerting:siem.queryRule/siem/rule/disable", + "alerting:siem.queryRule/siem/rule/muteAll", + "alerting:siem.queryRule/siem/rule/unmuteAll", + "alerting:siem.queryRule/siem/rule/muteAlert", + "alerting:siem.queryRule/siem/rule/unmuteAlert", + "alerting:siem.queryRule/siem/rule/snooze", + "alerting:siem.queryRule/siem/rule/bulkEdit", + "alerting:siem.queryRule/siem/rule/bulkDelete", + "alerting:siem.queryRule/siem/rule/bulkEnable", + "alerting:siem.queryRule/siem/rule/bulkDisable", + "alerting:siem.queryRule/siem/rule/unsnooze", + "alerting:siem.queryRule/siem/rule/runSoon", + "alerting:siem.queryRule/siem/rule/scheduleBackfill", + "alerting:siem.queryRule/siem/rule/deleteBackfill", + "alerting:siem.savedQueryRule/siem/rule/get", + "alerting:siem.savedQueryRule/siem/rule/getRuleState", + "alerting:siem.savedQueryRule/siem/rule/getAlertSummary", + "alerting:siem.savedQueryRule/siem/rule/getExecutionLog", + "alerting:siem.savedQueryRule/siem/rule/getActionErrorLog", + "alerting:siem.savedQueryRule/siem/rule/find", + "alerting:siem.savedQueryRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.savedQueryRule/siem/rule/getBackfill", + "alerting:siem.savedQueryRule/siem/rule/findBackfill", + "alerting:siem.savedQueryRule/siem/rule/create", + "alerting:siem.savedQueryRule/siem/rule/delete", + "alerting:siem.savedQueryRule/siem/rule/update", + "alerting:siem.savedQueryRule/siem/rule/updateApiKey", + "alerting:siem.savedQueryRule/siem/rule/enable", + "alerting:siem.savedQueryRule/siem/rule/disable", + "alerting:siem.savedQueryRule/siem/rule/muteAll", + "alerting:siem.savedQueryRule/siem/rule/unmuteAll", + "alerting:siem.savedQueryRule/siem/rule/muteAlert", + "alerting:siem.savedQueryRule/siem/rule/unmuteAlert", + "alerting:siem.savedQueryRule/siem/rule/snooze", + "alerting:siem.savedQueryRule/siem/rule/bulkEdit", + "alerting:siem.savedQueryRule/siem/rule/bulkDelete", + "alerting:siem.savedQueryRule/siem/rule/bulkEnable", + "alerting:siem.savedQueryRule/siem/rule/bulkDisable", + "alerting:siem.savedQueryRule/siem/rule/unsnooze", + "alerting:siem.savedQueryRule/siem/rule/runSoon", + "alerting:siem.savedQueryRule/siem/rule/scheduleBackfill", + "alerting:siem.savedQueryRule/siem/rule/deleteBackfill", + "alerting:siem.thresholdRule/siem/rule/get", + "alerting:siem.thresholdRule/siem/rule/getRuleState", + "alerting:siem.thresholdRule/siem/rule/getAlertSummary", + "alerting:siem.thresholdRule/siem/rule/getExecutionLog", + "alerting:siem.thresholdRule/siem/rule/getActionErrorLog", + "alerting:siem.thresholdRule/siem/rule/find", + "alerting:siem.thresholdRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.thresholdRule/siem/rule/getBackfill", + "alerting:siem.thresholdRule/siem/rule/findBackfill", + "alerting:siem.thresholdRule/siem/rule/create", + "alerting:siem.thresholdRule/siem/rule/delete", + "alerting:siem.thresholdRule/siem/rule/update", + "alerting:siem.thresholdRule/siem/rule/updateApiKey", + "alerting:siem.thresholdRule/siem/rule/enable", + "alerting:siem.thresholdRule/siem/rule/disable", + "alerting:siem.thresholdRule/siem/rule/muteAll", + "alerting:siem.thresholdRule/siem/rule/unmuteAll", + "alerting:siem.thresholdRule/siem/rule/muteAlert", + "alerting:siem.thresholdRule/siem/rule/unmuteAlert", + "alerting:siem.thresholdRule/siem/rule/snooze", + "alerting:siem.thresholdRule/siem/rule/bulkEdit", + "alerting:siem.thresholdRule/siem/rule/bulkDelete", + "alerting:siem.thresholdRule/siem/rule/bulkEnable", + "alerting:siem.thresholdRule/siem/rule/bulkDisable", + "alerting:siem.thresholdRule/siem/rule/unsnooze", + "alerting:siem.thresholdRule/siem/rule/runSoon", + "alerting:siem.thresholdRule/siem/rule/scheduleBackfill", + "alerting:siem.thresholdRule/siem/rule/deleteBackfill", + "alerting:siem.newTermsRule/siem/rule/get", + "alerting:siem.newTermsRule/siem/rule/getRuleState", + "alerting:siem.newTermsRule/siem/rule/getAlertSummary", + "alerting:siem.newTermsRule/siem/rule/getExecutionLog", + "alerting:siem.newTermsRule/siem/rule/getActionErrorLog", + "alerting:siem.newTermsRule/siem/rule/find", + "alerting:siem.newTermsRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.newTermsRule/siem/rule/getBackfill", + "alerting:siem.newTermsRule/siem/rule/findBackfill", + "alerting:siem.newTermsRule/siem/rule/create", + "alerting:siem.newTermsRule/siem/rule/delete", + "alerting:siem.newTermsRule/siem/rule/update", + "alerting:siem.newTermsRule/siem/rule/updateApiKey", + "alerting:siem.newTermsRule/siem/rule/enable", + "alerting:siem.newTermsRule/siem/rule/disable", + "alerting:siem.newTermsRule/siem/rule/muteAll", + "alerting:siem.newTermsRule/siem/rule/unmuteAll", + "alerting:siem.newTermsRule/siem/rule/muteAlert", + "alerting:siem.newTermsRule/siem/rule/unmuteAlert", + "alerting:siem.newTermsRule/siem/rule/snooze", + "alerting:siem.newTermsRule/siem/rule/bulkEdit", + "alerting:siem.newTermsRule/siem/rule/bulkDelete", + "alerting:siem.newTermsRule/siem/rule/bulkEnable", + "alerting:siem.newTermsRule/siem/rule/bulkDisable", + "alerting:siem.newTermsRule/siem/rule/unsnooze", + "alerting:siem.newTermsRule/siem/rule/runSoon", + "alerting:siem.newTermsRule/siem/rule/scheduleBackfill", + "alerting:siem.newTermsRule/siem/rule/deleteBackfill", + "alerting:siem.notifications/siem/alert/get", + "alerting:siem.notifications/siem/alert/find", + "alerting:siem.notifications/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.notifications/siem/alert/getAlertSummary", + "alerting:siem.notifications/siem/alert/update", + "alerting:siem.esqlRule/siem/alert/get", + "alerting:siem.esqlRule/siem/alert/find", + "alerting:siem.esqlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.esqlRule/siem/alert/getAlertSummary", + "alerting:siem.esqlRule/siem/alert/update", + "alerting:siem.eqlRule/siem/alert/get", + "alerting:siem.eqlRule/siem/alert/find", + "alerting:siem.eqlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.eqlRule/siem/alert/getAlertSummary", + "alerting:siem.eqlRule/siem/alert/update", + "alerting:siem.indicatorRule/siem/alert/get", + "alerting:siem.indicatorRule/siem/alert/find", + "alerting:siem.indicatorRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.indicatorRule/siem/alert/getAlertSummary", + "alerting:siem.indicatorRule/siem/alert/update", + "alerting:siem.mlRule/siem/alert/get", + "alerting:siem.mlRule/siem/alert/find", + "alerting:siem.mlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.mlRule/siem/alert/getAlertSummary", + "alerting:siem.mlRule/siem/alert/update", + "alerting:siem.queryRule/siem/alert/get", + "alerting:siem.queryRule/siem/alert/find", + "alerting:siem.queryRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.queryRule/siem/alert/getAlertSummary", + "alerting:siem.queryRule/siem/alert/update", + "alerting:siem.savedQueryRule/siem/alert/get", + "alerting:siem.savedQueryRule/siem/alert/find", + "alerting:siem.savedQueryRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.savedQueryRule/siem/alert/getAlertSummary", + "alerting:siem.savedQueryRule/siem/alert/update", + "alerting:siem.thresholdRule/siem/alert/get", + "alerting:siem.thresholdRule/siem/alert/find", + "alerting:siem.thresholdRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.thresholdRule/siem/alert/getAlertSummary", + "alerting:siem.thresholdRule/siem/alert/update", + "alerting:siem.newTermsRule/siem/alert/get", + "alerting:siem.newTermsRule/siem/alert/find", + "alerting:siem.newTermsRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.newTermsRule/siem/alert/getAlertSummary", + "alerting:siem.newTermsRule/siem/alert/update", + "api:fileUpload:analyzeFile", + "api:store_search_session", + "api:generateReport", + "app:discover", + "ui:catalogue/discover", + "ui:management/kibana/search_sessions", + "ui:management/insightsAndAlerting/reporting", + "ui:navLinks/discover", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:search/create", + "saved_object:search/bulk_create", + "saved_object:search/update", + "saved_object:search/bulk_update", + "saved_object:search/delete", + "saved_object:search/bulk_delete", + "saved_object:search/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "ui:discover/show", + "ui:discover/save", + "ui:discover/saveQuery", + "ui:discover/createShortUrl", + "ui:discover/storeSearchSession", + "ui:discover/generateCsv", + "api:bulkGetUserProfiles", + "api:downloadCsv", + "app:dashboards", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:dashboard/create", + "saved_object:dashboard/bulk_create", + "saved_object:dashboard/update", + "saved_object:dashboard/bulk_update", + "saved_object:dashboard/delete", + "saved_object:dashboard/bulk_delete", + "saved_object:dashboard/share_to_space", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "ui:dashboard/createNew", + "ui:dashboard/show", + "ui:dashboard/showWriteControls", + "ui:dashboard/saveQuery", + "ui:dashboard/createShortUrl", + "ui:dashboard/storeSearchSession", + "ui:dashboard/generateScreenshot", + "ui:dashboard/downloadCsv", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "saved_object:visualization/create", + "saved_object:visualization/bulk_create", + "saved_object:visualization/update", + "saved_object:visualization/bulk_update", + "saved_object:visualization/delete", + "saved_object:visualization/bulk_delete", + "saved_object:visualization/share_to_space", + "saved_object:lens/create", + "saved_object:lens/bulk_create", + "saved_object:lens/update", + "saved_object:lens/bulk_update", + "saved_object:lens/delete", + "saved_object:lens/bulk_delete", + "saved_object:lens/share_to_space", + "ui:visualize/show", + "ui:visualize/delete", + "ui:visualize/save", + "ui:visualize/saveQuery", + "ui:visualize/createShortUrl", + "ui:visualize/generateScreenshot", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "saved_object:map/create", + "saved_object:map/bulk_create", + "saved_object:map/update", + "saved_object:map/bulk_update", + "saved_object:map/delete", + "saved_object:map/bulk_delete", + "saved_object:map/share_to_space", + "ui:maps/save", + "ui:maps/show", + "ui:maps/saveQuery", + ], + "blocklist_all": Array [ + "login:", + "api:lists-all", + "api:lists-read", + "api:lists-summary", + "api:securitySolution-writeBlocklist", + "api:securitySolution-readBlocklist", + "saved_object:exception-list-agnostic/bulk_get", + "saved_object:exception-list-agnostic/get", + "saved_object:exception-list-agnostic/find", + "saved_object:exception-list-agnostic/open_point_in_time", + "saved_object:exception-list-agnostic/close_point_in_time", + "saved_object:exception-list-agnostic/create", + "saved_object:exception-list-agnostic/bulk_create", + "saved_object:exception-list-agnostic/update", + "saved_object:exception-list-agnostic/bulk_update", + "saved_object:exception-list-agnostic/delete", + "saved_object:exception-list-agnostic/bulk_delete", + "saved_object:exception-list-agnostic/share_to_space", + "ui:siem/writeBlocklist", + "ui:siem/readBlocklist", + ], + "blocklist_read": Array [ + "login:", + "api:lists-read", + "api:lists-summary", + "api:securitySolution-readBlocklist", + "ui:siem/readBlocklist", + ], + "endpoint_exceptions_all": Array [ + "login:", + "api:securitySolution-showEndpointExceptions", + "api:securitySolution-crudEndpointExceptions", + "ui:siem/showEndpointExceptions", + "ui:siem/crudEndpointExceptions", + ], + "endpoint_exceptions_read": Array [ + "login:", + "api:securitySolution-showEndpointExceptions", + "ui:siem/showEndpointExceptions", + ], + "endpoint_list_all": Array [ + "login:", + "api:securitySolution-writeEndpointList", + "api:securitySolution-readEndpointList", + "ui:siem/writeEndpointList", + "ui:siem/readEndpointList", + ], + "endpoint_list_read": Array [ + "login:", + "api:securitySolution-readEndpointList", + "ui:siem/readEndpointList", + ], + "event_filters_all": Array [ + "login:", + "api:lists-all", + "api:lists-read", + "api:lists-summary", + "api:securitySolution-writeEventFilters", + "api:securitySolution-readEventFilters", + "saved_object:exception-list-agnostic/bulk_get", + "saved_object:exception-list-agnostic/get", + "saved_object:exception-list-agnostic/find", + "saved_object:exception-list-agnostic/open_point_in_time", + "saved_object:exception-list-agnostic/close_point_in_time", + "saved_object:exception-list-agnostic/create", + "saved_object:exception-list-agnostic/bulk_create", + "saved_object:exception-list-agnostic/update", + "saved_object:exception-list-agnostic/bulk_update", + "saved_object:exception-list-agnostic/delete", + "saved_object:exception-list-agnostic/bulk_delete", + "saved_object:exception-list-agnostic/share_to_space", + "ui:siem/writeEventFilters", + "ui:siem/readEventFilters", + ], + "event_filters_read": Array [ + "login:", + "api:lists-read", + "api:lists-summary", + "api:securitySolution-readEventFilters", + "ui:siem/readEventFilters", + ], + "execute_operations_all": Array [ + "login:", + "api:securitySolution-writeExecuteOperations", + "ui:siem/writeExecuteOperations", + ], + "file_operations_all": Array [ + "login:", + "api:securitySolution-writeFileOperations", + "ui:siem/writeFileOperations", + ], + "host_isolation_all": Array [ + "login:", + "api:securitySolution-writeHostIsolationRelease", + "api:securitySolution-writeHostIsolation", + "ui:siem/writeHostIsolationRelease", + "ui:siem/writeHostIsolation", + ], + "host_isolation_exceptions_all": Array [ + "login:", + "api:lists-all", + "api:lists-read", + "api:lists-summary", + "api:securitySolution-deleteHostIsolationExceptions", + "api:securitySolution-readHostIsolationExceptions", + "api:securitySolution-accessHostIsolationExceptions", + "api:securitySolution-writeHostIsolationExceptions", + "saved_object:exception-list-agnostic/bulk_get", + "saved_object:exception-list-agnostic/get", + "saved_object:exception-list-agnostic/find", + "saved_object:exception-list-agnostic/open_point_in_time", + "saved_object:exception-list-agnostic/close_point_in_time", + "saved_object:exception-list-agnostic/create", + "saved_object:exception-list-agnostic/bulk_create", + "saved_object:exception-list-agnostic/update", + "saved_object:exception-list-agnostic/bulk_update", + "saved_object:exception-list-agnostic/delete", + "saved_object:exception-list-agnostic/bulk_delete", + "saved_object:exception-list-agnostic/share_to_space", + "ui:siem/readHostIsolationExceptions", + "ui:siem/deleteHostIsolationExceptions", + "ui:siem/accessHostIsolationExceptions", + "ui:siem/writeHostIsolationExceptions", + ], + "host_isolation_exceptions_read": Array [ + "login:", + "api:lists-read", + "api:lists-summary", + "api:securitySolution-readHostIsolationExceptions", + "api:securitySolution-accessHostIsolationExceptions", + "ui:siem/readHostIsolationExceptions", + "ui:siem/accessHostIsolationExceptions", + ], + "minimal_all": Array [ + "login:", + "api:securitySolution", + "api:lists-all", + "api:lists-read", + "api:lists-summary", + "api:rac", + "api:cloud-security-posture-all", + "api:cloud-security-posture-read", + "api:cloud-defend-all", + "api:cloud-defend-read", + "api:securitySolution-entity-analytics", + "api:securitySolution-threat-intelligence", + "app:securitySolution", + "app:csp", + "app:cloudDefend", + "app:kibana", + "ui:catalogue/securitySolution", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/securitySolution", + "ui:navLinks/csp", + "ui:navLinks/cloudDefend", + "ui:navLinks/kibana", + "saved_object:alert/bulk_get", + "saved_object:alert/get", + "saved_object:alert/find", + "saved_object:alert/open_point_in_time", + "saved_object:alert/close_point_in_time", + "saved_object:alert/create", + "saved_object:alert/bulk_create", + "saved_object:alert/update", + "saved_object:alert/bulk_update", + "saved_object:alert/delete", + "saved_object:alert/bulk_delete", + "saved_object:alert/share_to_space", + "saved_object:exception-list/bulk_get", + "saved_object:exception-list/get", + "saved_object:exception-list/find", + "saved_object:exception-list/open_point_in_time", + "saved_object:exception-list/close_point_in_time", + "saved_object:exception-list/create", + "saved_object:exception-list/bulk_create", + "saved_object:exception-list/update", + "saved_object:exception-list/bulk_update", + "saved_object:exception-list/delete", + "saved_object:exception-list/bulk_delete", + "saved_object:exception-list/share_to_space", + "saved_object:exception-list-agnostic/bulk_get", + "saved_object:exception-list-agnostic/get", + "saved_object:exception-list-agnostic/find", + "saved_object:exception-list-agnostic/open_point_in_time", + "saved_object:exception-list-agnostic/close_point_in_time", + "saved_object:exception-list-agnostic/create", + "saved_object:exception-list-agnostic/bulk_create", + "saved_object:exception-list-agnostic/update", + "saved_object:exception-list-agnostic/bulk_update", + "saved_object:exception-list-agnostic/delete", + "saved_object:exception-list-agnostic/bulk_delete", + "saved_object:exception-list-agnostic/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:index-pattern/create", + "saved_object:index-pattern/bulk_create", + "saved_object:index-pattern/update", + "saved_object:index-pattern/bulk_update", + "saved_object:index-pattern/delete", + "saved_object:index-pattern/bulk_delete", + "saved_object:index-pattern/share_to_space", + "saved_object:siem-ui-timeline-note/bulk_get", + "saved_object:siem-ui-timeline-note/get", + "saved_object:siem-ui-timeline-note/find", + "saved_object:siem-ui-timeline-note/open_point_in_time", + "saved_object:siem-ui-timeline-note/close_point_in_time", + "saved_object:siem-ui-timeline-note/create", + "saved_object:siem-ui-timeline-note/bulk_create", + "saved_object:siem-ui-timeline-note/update", + "saved_object:siem-ui-timeline-note/bulk_update", + "saved_object:siem-ui-timeline-note/delete", + "saved_object:siem-ui-timeline-note/bulk_delete", + "saved_object:siem-ui-timeline-note/share_to_space", + "saved_object:siem-ui-timeline-pinned-event/bulk_get", + "saved_object:siem-ui-timeline-pinned-event/get", + "saved_object:siem-ui-timeline-pinned-event/find", + "saved_object:siem-ui-timeline-pinned-event/open_point_in_time", + "saved_object:siem-ui-timeline-pinned-event/close_point_in_time", + "saved_object:siem-ui-timeline-pinned-event/create", + "saved_object:siem-ui-timeline-pinned-event/bulk_create", + "saved_object:siem-ui-timeline-pinned-event/update", + "saved_object:siem-ui-timeline-pinned-event/bulk_update", + "saved_object:siem-ui-timeline-pinned-event/delete", + "saved_object:siem-ui-timeline-pinned-event/bulk_delete", + "saved_object:siem-ui-timeline-pinned-event/share_to_space", + "saved_object:siem-detection-engine-rule-actions/bulk_get", + "saved_object:siem-detection-engine-rule-actions/get", + "saved_object:siem-detection-engine-rule-actions/find", + "saved_object:siem-detection-engine-rule-actions/open_point_in_time", + "saved_object:siem-detection-engine-rule-actions/close_point_in_time", + "saved_object:siem-detection-engine-rule-actions/create", + "saved_object:siem-detection-engine-rule-actions/bulk_create", + "saved_object:siem-detection-engine-rule-actions/update", + "saved_object:siem-detection-engine-rule-actions/bulk_update", + "saved_object:siem-detection-engine-rule-actions/delete", + "saved_object:siem-detection-engine-rule-actions/bulk_delete", + "saved_object:siem-detection-engine-rule-actions/share_to_space", + "saved_object:security-rule/bulk_get", + "saved_object:security-rule/get", + "saved_object:security-rule/find", + "saved_object:security-rule/open_point_in_time", + "saved_object:security-rule/close_point_in_time", + "saved_object:security-rule/create", + "saved_object:security-rule/bulk_create", + "saved_object:security-rule/update", + "saved_object:security-rule/bulk_update", + "saved_object:security-rule/delete", + "saved_object:security-rule/bulk_delete", + "saved_object:security-rule/share_to_space", + "saved_object:siem-ui-timeline/bulk_get", + "saved_object:siem-ui-timeline/get", + "saved_object:siem-ui-timeline/find", + "saved_object:siem-ui-timeline/open_point_in_time", + "saved_object:siem-ui-timeline/close_point_in_time", + "saved_object:siem-ui-timeline/create", + "saved_object:siem-ui-timeline/bulk_create", + "saved_object:siem-ui-timeline/update", + "saved_object:siem-ui-timeline/bulk_update", + "saved_object:siem-ui-timeline/delete", + "saved_object:siem-ui-timeline/bulk_delete", + "saved_object:siem-ui-timeline/share_to_space", + "saved_object:endpoint:user-artifact-manifest/bulk_get", + "saved_object:endpoint:user-artifact-manifest/get", + "saved_object:endpoint:user-artifact-manifest/find", + "saved_object:endpoint:user-artifact-manifest/open_point_in_time", + "saved_object:endpoint:user-artifact-manifest/close_point_in_time", + "saved_object:endpoint:user-artifact-manifest/create", + "saved_object:endpoint:user-artifact-manifest/bulk_create", + "saved_object:endpoint:user-artifact-manifest/update", + "saved_object:endpoint:user-artifact-manifest/bulk_update", + "saved_object:endpoint:user-artifact-manifest/delete", + "saved_object:endpoint:user-artifact-manifest/bulk_delete", + "saved_object:endpoint:user-artifact-manifest/share_to_space", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_get", + "saved_object:endpoint:unified-user-artifact-manifest/get", + "saved_object:endpoint:unified-user-artifact-manifest/find", + "saved_object:endpoint:unified-user-artifact-manifest/open_point_in_time", + "saved_object:endpoint:unified-user-artifact-manifest/close_point_in_time", + "saved_object:endpoint:unified-user-artifact-manifest/create", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_create", + "saved_object:endpoint:unified-user-artifact-manifest/update", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_update", + "saved_object:endpoint:unified-user-artifact-manifest/delete", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_delete", + "saved_object:endpoint:unified-user-artifact-manifest/share_to_space", + "saved_object:security-solution-signals-migration/bulk_get", + "saved_object:security-solution-signals-migration/get", + "saved_object:security-solution-signals-migration/find", + "saved_object:security-solution-signals-migration/open_point_in_time", + "saved_object:security-solution-signals-migration/close_point_in_time", + "saved_object:security-solution-signals-migration/create", + "saved_object:security-solution-signals-migration/bulk_create", + "saved_object:security-solution-signals-migration/update", + "saved_object:security-solution-signals-migration/bulk_update", + "saved_object:security-solution-signals-migration/delete", + "saved_object:security-solution-signals-migration/bulk_delete", + "saved_object:security-solution-signals-migration/share_to_space", + "saved_object:risk-engine-configuration/bulk_get", + "saved_object:risk-engine-configuration/get", + "saved_object:risk-engine-configuration/find", + "saved_object:risk-engine-configuration/open_point_in_time", + "saved_object:risk-engine-configuration/close_point_in_time", + "saved_object:risk-engine-configuration/create", + "saved_object:risk-engine-configuration/bulk_create", + "saved_object:risk-engine-configuration/update", + "saved_object:risk-engine-configuration/bulk_update", + "saved_object:risk-engine-configuration/delete", + "saved_object:risk-engine-configuration/bulk_delete", + "saved_object:risk-engine-configuration/share_to_space", + "saved_object:policy-settings-protection-updates-note/bulk_get", + "saved_object:policy-settings-protection-updates-note/get", + "saved_object:policy-settings-protection-updates-note/find", + "saved_object:policy-settings-protection-updates-note/open_point_in_time", + "saved_object:policy-settings-protection-updates-note/close_point_in_time", + "saved_object:policy-settings-protection-updates-note/create", + "saved_object:policy-settings-protection-updates-note/bulk_create", + "saved_object:policy-settings-protection-updates-note/update", + "saved_object:policy-settings-protection-updates-note/bulk_update", + "saved_object:policy-settings-protection-updates-note/delete", + "saved_object:policy-settings-protection-updates-note/bulk_delete", + "saved_object:policy-settings-protection-updates-note/share_to_space", + "saved_object:csp_rule/bulk_get", + "saved_object:csp_rule/get", + "saved_object:csp_rule/find", + "saved_object:csp_rule/open_point_in_time", + "saved_object:csp_rule/close_point_in_time", + "saved_object:csp_rule/create", + "saved_object:csp_rule/bulk_create", + "saved_object:csp_rule/update", + "saved_object:csp_rule/bulk_update", + "saved_object:csp_rule/delete", + "saved_object:csp_rule/bulk_delete", + "saved_object:csp_rule/share_to_space", + "saved_object:cloud-security-posture-settings/bulk_get", + "saved_object:cloud-security-posture-settings/get", + "saved_object:cloud-security-posture-settings/find", + "saved_object:cloud-security-posture-settings/open_point_in_time", + "saved_object:cloud-security-posture-settings/close_point_in_time", + "saved_object:cloud-security-posture-settings/create", + "saved_object:cloud-security-posture-settings/bulk_create", + "saved_object:cloud-security-posture-settings/update", + "saved_object:cloud-security-posture-settings/bulk_update", + "saved_object:cloud-security-posture-settings/delete", + "saved_object:cloud-security-posture-settings/bulk_delete", + "saved_object:cloud-security-posture-settings/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:siem/show", + "ui:siem/crud", + "ui:siem/entity-analytics", + "ui:siem/investigation-guide", + "ui:siem/investigation-guide-interactions", + "ui:siem/threat-intelligence", + "alerting:siem.notifications/siem/rule/get", + "alerting:siem.notifications/siem/rule/getRuleState", + "alerting:siem.notifications/siem/rule/getAlertSummary", + "alerting:siem.notifications/siem/rule/getExecutionLog", + "alerting:siem.notifications/siem/rule/getActionErrorLog", + "alerting:siem.notifications/siem/rule/find", + "alerting:siem.notifications/siem/rule/getRuleExecutionKPI", + "alerting:siem.notifications/siem/rule/getBackfill", + "alerting:siem.notifications/siem/rule/findBackfill", + "alerting:siem.notifications/siem/rule/create", + "alerting:siem.notifications/siem/rule/delete", + "alerting:siem.notifications/siem/rule/update", + "alerting:siem.notifications/siem/rule/updateApiKey", + "alerting:siem.notifications/siem/rule/enable", + "alerting:siem.notifications/siem/rule/disable", + "alerting:siem.notifications/siem/rule/muteAll", + "alerting:siem.notifications/siem/rule/unmuteAll", + "alerting:siem.notifications/siem/rule/muteAlert", + "alerting:siem.notifications/siem/rule/unmuteAlert", + "alerting:siem.notifications/siem/rule/snooze", + "alerting:siem.notifications/siem/rule/bulkEdit", + "alerting:siem.notifications/siem/rule/bulkDelete", + "alerting:siem.notifications/siem/rule/bulkEnable", + "alerting:siem.notifications/siem/rule/bulkDisable", + "alerting:siem.notifications/siem/rule/unsnooze", + "alerting:siem.notifications/siem/rule/runSoon", + "alerting:siem.notifications/siem/rule/scheduleBackfill", + "alerting:siem.notifications/siem/rule/deleteBackfill", + "alerting:siem.esqlRule/siem/rule/get", + "alerting:siem.esqlRule/siem/rule/getRuleState", + "alerting:siem.esqlRule/siem/rule/getAlertSummary", + "alerting:siem.esqlRule/siem/rule/getExecutionLog", + "alerting:siem.esqlRule/siem/rule/getActionErrorLog", + "alerting:siem.esqlRule/siem/rule/find", + "alerting:siem.esqlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.esqlRule/siem/rule/getBackfill", + "alerting:siem.esqlRule/siem/rule/findBackfill", + "alerting:siem.esqlRule/siem/rule/create", + "alerting:siem.esqlRule/siem/rule/delete", + "alerting:siem.esqlRule/siem/rule/update", + "alerting:siem.esqlRule/siem/rule/updateApiKey", + "alerting:siem.esqlRule/siem/rule/enable", + "alerting:siem.esqlRule/siem/rule/disable", + "alerting:siem.esqlRule/siem/rule/muteAll", + "alerting:siem.esqlRule/siem/rule/unmuteAll", + "alerting:siem.esqlRule/siem/rule/muteAlert", + "alerting:siem.esqlRule/siem/rule/unmuteAlert", + "alerting:siem.esqlRule/siem/rule/snooze", + "alerting:siem.esqlRule/siem/rule/bulkEdit", + "alerting:siem.esqlRule/siem/rule/bulkDelete", + "alerting:siem.esqlRule/siem/rule/bulkEnable", + "alerting:siem.esqlRule/siem/rule/bulkDisable", + "alerting:siem.esqlRule/siem/rule/unsnooze", + "alerting:siem.esqlRule/siem/rule/runSoon", + "alerting:siem.esqlRule/siem/rule/scheduleBackfill", + "alerting:siem.esqlRule/siem/rule/deleteBackfill", + "alerting:siem.eqlRule/siem/rule/get", + "alerting:siem.eqlRule/siem/rule/getRuleState", + "alerting:siem.eqlRule/siem/rule/getAlertSummary", + "alerting:siem.eqlRule/siem/rule/getExecutionLog", + "alerting:siem.eqlRule/siem/rule/getActionErrorLog", + "alerting:siem.eqlRule/siem/rule/find", + "alerting:siem.eqlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.eqlRule/siem/rule/getBackfill", + "alerting:siem.eqlRule/siem/rule/findBackfill", + "alerting:siem.eqlRule/siem/rule/create", + "alerting:siem.eqlRule/siem/rule/delete", + "alerting:siem.eqlRule/siem/rule/update", + "alerting:siem.eqlRule/siem/rule/updateApiKey", + "alerting:siem.eqlRule/siem/rule/enable", + "alerting:siem.eqlRule/siem/rule/disable", + "alerting:siem.eqlRule/siem/rule/muteAll", + "alerting:siem.eqlRule/siem/rule/unmuteAll", + "alerting:siem.eqlRule/siem/rule/muteAlert", + "alerting:siem.eqlRule/siem/rule/unmuteAlert", + "alerting:siem.eqlRule/siem/rule/snooze", + "alerting:siem.eqlRule/siem/rule/bulkEdit", + "alerting:siem.eqlRule/siem/rule/bulkDelete", + "alerting:siem.eqlRule/siem/rule/bulkEnable", + "alerting:siem.eqlRule/siem/rule/bulkDisable", + "alerting:siem.eqlRule/siem/rule/unsnooze", + "alerting:siem.eqlRule/siem/rule/runSoon", + "alerting:siem.eqlRule/siem/rule/scheduleBackfill", + "alerting:siem.eqlRule/siem/rule/deleteBackfill", + "alerting:siem.indicatorRule/siem/rule/get", + "alerting:siem.indicatorRule/siem/rule/getRuleState", + "alerting:siem.indicatorRule/siem/rule/getAlertSummary", + "alerting:siem.indicatorRule/siem/rule/getExecutionLog", + "alerting:siem.indicatorRule/siem/rule/getActionErrorLog", + "alerting:siem.indicatorRule/siem/rule/find", + "alerting:siem.indicatorRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.indicatorRule/siem/rule/getBackfill", + "alerting:siem.indicatorRule/siem/rule/findBackfill", + "alerting:siem.indicatorRule/siem/rule/create", + "alerting:siem.indicatorRule/siem/rule/delete", + "alerting:siem.indicatorRule/siem/rule/update", + "alerting:siem.indicatorRule/siem/rule/updateApiKey", + "alerting:siem.indicatorRule/siem/rule/enable", + "alerting:siem.indicatorRule/siem/rule/disable", + "alerting:siem.indicatorRule/siem/rule/muteAll", + "alerting:siem.indicatorRule/siem/rule/unmuteAll", + "alerting:siem.indicatorRule/siem/rule/muteAlert", + "alerting:siem.indicatorRule/siem/rule/unmuteAlert", + "alerting:siem.indicatorRule/siem/rule/snooze", + "alerting:siem.indicatorRule/siem/rule/bulkEdit", + "alerting:siem.indicatorRule/siem/rule/bulkDelete", + "alerting:siem.indicatorRule/siem/rule/bulkEnable", + "alerting:siem.indicatorRule/siem/rule/bulkDisable", + "alerting:siem.indicatorRule/siem/rule/unsnooze", + "alerting:siem.indicatorRule/siem/rule/runSoon", + "alerting:siem.indicatorRule/siem/rule/scheduleBackfill", + "alerting:siem.indicatorRule/siem/rule/deleteBackfill", + "alerting:siem.mlRule/siem/rule/get", + "alerting:siem.mlRule/siem/rule/getRuleState", + "alerting:siem.mlRule/siem/rule/getAlertSummary", + "alerting:siem.mlRule/siem/rule/getExecutionLog", + "alerting:siem.mlRule/siem/rule/getActionErrorLog", + "alerting:siem.mlRule/siem/rule/find", + "alerting:siem.mlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.mlRule/siem/rule/getBackfill", + "alerting:siem.mlRule/siem/rule/findBackfill", + "alerting:siem.mlRule/siem/rule/create", + "alerting:siem.mlRule/siem/rule/delete", + "alerting:siem.mlRule/siem/rule/update", + "alerting:siem.mlRule/siem/rule/updateApiKey", + "alerting:siem.mlRule/siem/rule/enable", + "alerting:siem.mlRule/siem/rule/disable", + "alerting:siem.mlRule/siem/rule/muteAll", + "alerting:siem.mlRule/siem/rule/unmuteAll", + "alerting:siem.mlRule/siem/rule/muteAlert", + "alerting:siem.mlRule/siem/rule/unmuteAlert", + "alerting:siem.mlRule/siem/rule/snooze", + "alerting:siem.mlRule/siem/rule/bulkEdit", + "alerting:siem.mlRule/siem/rule/bulkDelete", + "alerting:siem.mlRule/siem/rule/bulkEnable", + "alerting:siem.mlRule/siem/rule/bulkDisable", + "alerting:siem.mlRule/siem/rule/unsnooze", + "alerting:siem.mlRule/siem/rule/runSoon", + "alerting:siem.mlRule/siem/rule/scheduleBackfill", + "alerting:siem.mlRule/siem/rule/deleteBackfill", + "alerting:siem.queryRule/siem/rule/get", + "alerting:siem.queryRule/siem/rule/getRuleState", + "alerting:siem.queryRule/siem/rule/getAlertSummary", + "alerting:siem.queryRule/siem/rule/getExecutionLog", + "alerting:siem.queryRule/siem/rule/getActionErrorLog", + "alerting:siem.queryRule/siem/rule/find", + "alerting:siem.queryRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.queryRule/siem/rule/getBackfill", + "alerting:siem.queryRule/siem/rule/findBackfill", + "alerting:siem.queryRule/siem/rule/create", + "alerting:siem.queryRule/siem/rule/delete", + "alerting:siem.queryRule/siem/rule/update", + "alerting:siem.queryRule/siem/rule/updateApiKey", + "alerting:siem.queryRule/siem/rule/enable", + "alerting:siem.queryRule/siem/rule/disable", + "alerting:siem.queryRule/siem/rule/muteAll", + "alerting:siem.queryRule/siem/rule/unmuteAll", + "alerting:siem.queryRule/siem/rule/muteAlert", + "alerting:siem.queryRule/siem/rule/unmuteAlert", + "alerting:siem.queryRule/siem/rule/snooze", + "alerting:siem.queryRule/siem/rule/bulkEdit", + "alerting:siem.queryRule/siem/rule/bulkDelete", + "alerting:siem.queryRule/siem/rule/bulkEnable", + "alerting:siem.queryRule/siem/rule/bulkDisable", + "alerting:siem.queryRule/siem/rule/unsnooze", + "alerting:siem.queryRule/siem/rule/runSoon", + "alerting:siem.queryRule/siem/rule/scheduleBackfill", + "alerting:siem.queryRule/siem/rule/deleteBackfill", + "alerting:siem.savedQueryRule/siem/rule/get", + "alerting:siem.savedQueryRule/siem/rule/getRuleState", + "alerting:siem.savedQueryRule/siem/rule/getAlertSummary", + "alerting:siem.savedQueryRule/siem/rule/getExecutionLog", + "alerting:siem.savedQueryRule/siem/rule/getActionErrorLog", + "alerting:siem.savedQueryRule/siem/rule/find", + "alerting:siem.savedQueryRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.savedQueryRule/siem/rule/getBackfill", + "alerting:siem.savedQueryRule/siem/rule/findBackfill", + "alerting:siem.savedQueryRule/siem/rule/create", + "alerting:siem.savedQueryRule/siem/rule/delete", + "alerting:siem.savedQueryRule/siem/rule/update", + "alerting:siem.savedQueryRule/siem/rule/updateApiKey", + "alerting:siem.savedQueryRule/siem/rule/enable", + "alerting:siem.savedQueryRule/siem/rule/disable", + "alerting:siem.savedQueryRule/siem/rule/muteAll", + "alerting:siem.savedQueryRule/siem/rule/unmuteAll", + "alerting:siem.savedQueryRule/siem/rule/muteAlert", + "alerting:siem.savedQueryRule/siem/rule/unmuteAlert", + "alerting:siem.savedQueryRule/siem/rule/snooze", + "alerting:siem.savedQueryRule/siem/rule/bulkEdit", + "alerting:siem.savedQueryRule/siem/rule/bulkDelete", + "alerting:siem.savedQueryRule/siem/rule/bulkEnable", + "alerting:siem.savedQueryRule/siem/rule/bulkDisable", + "alerting:siem.savedQueryRule/siem/rule/unsnooze", + "alerting:siem.savedQueryRule/siem/rule/runSoon", + "alerting:siem.savedQueryRule/siem/rule/scheduleBackfill", + "alerting:siem.savedQueryRule/siem/rule/deleteBackfill", + "alerting:siem.thresholdRule/siem/rule/get", + "alerting:siem.thresholdRule/siem/rule/getRuleState", + "alerting:siem.thresholdRule/siem/rule/getAlertSummary", + "alerting:siem.thresholdRule/siem/rule/getExecutionLog", + "alerting:siem.thresholdRule/siem/rule/getActionErrorLog", + "alerting:siem.thresholdRule/siem/rule/find", + "alerting:siem.thresholdRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.thresholdRule/siem/rule/getBackfill", + "alerting:siem.thresholdRule/siem/rule/findBackfill", + "alerting:siem.thresholdRule/siem/rule/create", + "alerting:siem.thresholdRule/siem/rule/delete", + "alerting:siem.thresholdRule/siem/rule/update", + "alerting:siem.thresholdRule/siem/rule/updateApiKey", + "alerting:siem.thresholdRule/siem/rule/enable", + "alerting:siem.thresholdRule/siem/rule/disable", + "alerting:siem.thresholdRule/siem/rule/muteAll", + "alerting:siem.thresholdRule/siem/rule/unmuteAll", + "alerting:siem.thresholdRule/siem/rule/muteAlert", + "alerting:siem.thresholdRule/siem/rule/unmuteAlert", + "alerting:siem.thresholdRule/siem/rule/snooze", + "alerting:siem.thresholdRule/siem/rule/bulkEdit", + "alerting:siem.thresholdRule/siem/rule/bulkDelete", + "alerting:siem.thresholdRule/siem/rule/bulkEnable", + "alerting:siem.thresholdRule/siem/rule/bulkDisable", + "alerting:siem.thresholdRule/siem/rule/unsnooze", + "alerting:siem.thresholdRule/siem/rule/runSoon", + "alerting:siem.thresholdRule/siem/rule/scheduleBackfill", + "alerting:siem.thresholdRule/siem/rule/deleteBackfill", + "alerting:siem.newTermsRule/siem/rule/get", + "alerting:siem.newTermsRule/siem/rule/getRuleState", + "alerting:siem.newTermsRule/siem/rule/getAlertSummary", + "alerting:siem.newTermsRule/siem/rule/getExecutionLog", + "alerting:siem.newTermsRule/siem/rule/getActionErrorLog", + "alerting:siem.newTermsRule/siem/rule/find", + "alerting:siem.newTermsRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.newTermsRule/siem/rule/getBackfill", + "alerting:siem.newTermsRule/siem/rule/findBackfill", + "alerting:siem.newTermsRule/siem/rule/create", + "alerting:siem.newTermsRule/siem/rule/delete", + "alerting:siem.newTermsRule/siem/rule/update", + "alerting:siem.newTermsRule/siem/rule/updateApiKey", + "alerting:siem.newTermsRule/siem/rule/enable", + "alerting:siem.newTermsRule/siem/rule/disable", + "alerting:siem.newTermsRule/siem/rule/muteAll", + "alerting:siem.newTermsRule/siem/rule/unmuteAll", + "alerting:siem.newTermsRule/siem/rule/muteAlert", + "alerting:siem.newTermsRule/siem/rule/unmuteAlert", + "alerting:siem.newTermsRule/siem/rule/snooze", + "alerting:siem.newTermsRule/siem/rule/bulkEdit", + "alerting:siem.newTermsRule/siem/rule/bulkDelete", + "alerting:siem.newTermsRule/siem/rule/bulkEnable", + "alerting:siem.newTermsRule/siem/rule/bulkDisable", + "alerting:siem.newTermsRule/siem/rule/unsnooze", + "alerting:siem.newTermsRule/siem/rule/runSoon", + "alerting:siem.newTermsRule/siem/rule/scheduleBackfill", + "alerting:siem.newTermsRule/siem/rule/deleteBackfill", + "alerting:siem.notifications/siem/alert/get", + "alerting:siem.notifications/siem/alert/find", + "alerting:siem.notifications/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.notifications/siem/alert/getAlertSummary", + "alerting:siem.notifications/siem/alert/update", + "alerting:siem.esqlRule/siem/alert/get", + "alerting:siem.esqlRule/siem/alert/find", + "alerting:siem.esqlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.esqlRule/siem/alert/getAlertSummary", + "alerting:siem.esqlRule/siem/alert/update", + "alerting:siem.eqlRule/siem/alert/get", + "alerting:siem.eqlRule/siem/alert/find", + "alerting:siem.eqlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.eqlRule/siem/alert/getAlertSummary", + "alerting:siem.eqlRule/siem/alert/update", + "alerting:siem.indicatorRule/siem/alert/get", + "alerting:siem.indicatorRule/siem/alert/find", + "alerting:siem.indicatorRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.indicatorRule/siem/alert/getAlertSummary", + "alerting:siem.indicatorRule/siem/alert/update", + "alerting:siem.mlRule/siem/alert/get", + "alerting:siem.mlRule/siem/alert/find", + "alerting:siem.mlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.mlRule/siem/alert/getAlertSummary", + "alerting:siem.mlRule/siem/alert/update", + "alerting:siem.queryRule/siem/alert/get", + "alerting:siem.queryRule/siem/alert/find", + "alerting:siem.queryRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.queryRule/siem/alert/getAlertSummary", + "alerting:siem.queryRule/siem/alert/update", + "alerting:siem.savedQueryRule/siem/alert/get", + "alerting:siem.savedQueryRule/siem/alert/find", + "alerting:siem.savedQueryRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.savedQueryRule/siem/alert/getAlertSummary", + "alerting:siem.savedQueryRule/siem/alert/update", + "alerting:siem.thresholdRule/siem/alert/get", + "alerting:siem.thresholdRule/siem/alert/find", + "alerting:siem.thresholdRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.thresholdRule/siem/alert/getAlertSummary", + "alerting:siem.thresholdRule/siem/alert/update", + "alerting:siem.newTermsRule/siem/alert/get", + "alerting:siem.newTermsRule/siem/alert/find", + "alerting:siem.newTermsRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.newTermsRule/siem/alert/getAlertSummary", + "alerting:siem.newTermsRule/siem/alert/update", + "api:fileUpload:analyzeFile", + "api:store_search_session", + "api:generateReport", + "app:discover", + "ui:catalogue/discover", + "ui:management/kibana/search_sessions", + "ui:management/insightsAndAlerting/reporting", + "ui:navLinks/discover", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:search/create", + "saved_object:search/bulk_create", + "saved_object:search/update", + "saved_object:search/bulk_update", + "saved_object:search/delete", + "saved_object:search/bulk_delete", + "saved_object:search/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:search-session/bulk_get", + "saved_object:search-session/get", + "saved_object:search-session/find", + "saved_object:search-session/open_point_in_time", + "saved_object:search-session/close_point_in_time", + "saved_object:search-session/create", + "saved_object:search-session/bulk_create", + "saved_object:search-session/update", + "saved_object:search-session/bulk_update", + "saved_object:search-session/delete", + "saved_object:search-session/bulk_delete", + "saved_object:search-session/share_to_space", + "ui:discover/show", + "ui:discover/save", + "ui:discover/saveQuery", + "ui:discover/createShortUrl", + "ui:discover/storeSearchSession", + "ui:discover/generateCsv", + "api:bulkGetUserProfiles", + "api:downloadCsv", + "app:dashboards", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:dashboard/create", + "saved_object:dashboard/bulk_create", + "saved_object:dashboard/update", + "saved_object:dashboard/bulk_update", + "saved_object:dashboard/delete", + "saved_object:dashboard/bulk_delete", + "saved_object:dashboard/share_to_space", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "ui:dashboard/createNew", + "ui:dashboard/show", + "ui:dashboard/showWriteControls", + "ui:dashboard/saveQuery", + "ui:dashboard/createShortUrl", + "ui:dashboard/storeSearchSession", + "ui:dashboard/generateScreenshot", + "ui:dashboard/downloadCsv", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "saved_object:visualization/create", + "saved_object:visualization/bulk_create", + "saved_object:visualization/update", + "saved_object:visualization/bulk_update", + "saved_object:visualization/delete", + "saved_object:visualization/bulk_delete", + "saved_object:visualization/share_to_space", + "saved_object:lens/create", + "saved_object:lens/bulk_create", + "saved_object:lens/update", + "saved_object:lens/bulk_update", + "saved_object:lens/delete", + "saved_object:lens/bulk_delete", + "saved_object:lens/share_to_space", + "ui:visualize/show", + "ui:visualize/delete", + "ui:visualize/save", + "ui:visualize/saveQuery", + "ui:visualize/createShortUrl", + "ui:visualize/generateScreenshot", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "saved_object:map/create", + "saved_object:map/bulk_create", + "saved_object:map/update", + "saved_object:map/bulk_update", + "saved_object:map/delete", + "saved_object:map/bulk_delete", + "saved_object:map/share_to_space", + "ui:maps/save", + "ui:maps/show", + "ui:maps/saveQuery", + ], + "minimal_read": Array [ + "login:", + "api:securitySolution", + "api:lists-read", + "api:rac", + "api:cloud-security-posture-read", + "api:cloud-defend-read", + "api:securitySolution-entity-analytics", + "api:securitySolution-threat-intelligence", + "app:securitySolution", + "app:csp", + "app:cloudDefend", + "app:kibana", + "ui:catalogue/securitySolution", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/securitySolution", + "ui:navLinks/csp", + "ui:navLinks/cloudDefend", + "ui:navLinks/kibana", + "saved_object:exception-list/bulk_get", + "saved_object:exception-list/get", + "saved_object:exception-list/find", + "saved_object:exception-list/open_point_in_time", + "saved_object:exception-list/close_point_in_time", + "saved_object:exception-list-agnostic/bulk_get", + "saved_object:exception-list-agnostic/get", + "saved_object:exception-list-agnostic/find", + "saved_object:exception-list-agnostic/open_point_in_time", + "saved_object:exception-list-agnostic/close_point_in_time", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:siem-ui-timeline-note/bulk_get", + "saved_object:siem-ui-timeline-note/get", + "saved_object:siem-ui-timeline-note/find", + "saved_object:siem-ui-timeline-note/open_point_in_time", + "saved_object:siem-ui-timeline-note/close_point_in_time", + "saved_object:siem-ui-timeline-pinned-event/bulk_get", + "saved_object:siem-ui-timeline-pinned-event/get", + "saved_object:siem-ui-timeline-pinned-event/find", + "saved_object:siem-ui-timeline-pinned-event/open_point_in_time", + "saved_object:siem-ui-timeline-pinned-event/close_point_in_time", + "saved_object:siem-detection-engine-rule-actions/bulk_get", + "saved_object:siem-detection-engine-rule-actions/get", + "saved_object:siem-detection-engine-rule-actions/find", + "saved_object:siem-detection-engine-rule-actions/open_point_in_time", + "saved_object:siem-detection-engine-rule-actions/close_point_in_time", + "saved_object:security-rule/bulk_get", + "saved_object:security-rule/get", + "saved_object:security-rule/find", + "saved_object:security-rule/open_point_in_time", + "saved_object:security-rule/close_point_in_time", + "saved_object:siem-ui-timeline/bulk_get", + "saved_object:siem-ui-timeline/get", + "saved_object:siem-ui-timeline/find", + "saved_object:siem-ui-timeline/open_point_in_time", + "saved_object:siem-ui-timeline/close_point_in_time", + "saved_object:endpoint:user-artifact-manifest/bulk_get", + "saved_object:endpoint:user-artifact-manifest/get", + "saved_object:endpoint:user-artifact-manifest/find", + "saved_object:endpoint:user-artifact-manifest/open_point_in_time", + "saved_object:endpoint:user-artifact-manifest/close_point_in_time", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_get", + "saved_object:endpoint:unified-user-artifact-manifest/get", + "saved_object:endpoint:unified-user-artifact-manifest/find", + "saved_object:endpoint:unified-user-artifact-manifest/open_point_in_time", + "saved_object:endpoint:unified-user-artifact-manifest/close_point_in_time", + "saved_object:security-solution-signals-migration/bulk_get", + "saved_object:security-solution-signals-migration/get", + "saved_object:security-solution-signals-migration/find", + "saved_object:security-solution-signals-migration/open_point_in_time", + "saved_object:security-solution-signals-migration/close_point_in_time", + "saved_object:risk-engine-configuration/bulk_get", + "saved_object:risk-engine-configuration/get", + "saved_object:risk-engine-configuration/find", + "saved_object:risk-engine-configuration/open_point_in_time", + "saved_object:risk-engine-configuration/close_point_in_time", + "saved_object:policy-settings-protection-updates-note/bulk_get", + "saved_object:policy-settings-protection-updates-note/get", + "saved_object:policy-settings-protection-updates-note/find", + "saved_object:policy-settings-protection-updates-note/open_point_in_time", + "saved_object:policy-settings-protection-updates-note/close_point_in_time", + "saved_object:csp_rule/bulk_get", + "saved_object:csp_rule/get", + "saved_object:csp_rule/find", + "saved_object:csp_rule/open_point_in_time", + "saved_object:csp_rule/close_point_in_time", + "saved_object:cloud-security-posture-settings/bulk_get", + "saved_object:cloud-security-posture-settings/get", + "saved_object:cloud-security-posture-settings/find", + "saved_object:cloud-security-posture-settings/open_point_in_time", + "saved_object:cloud-security-posture-settings/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:siem/show", + "ui:siem/entity-analytics", + "ui:siem/investigation-guide", + "ui:siem/investigation-guide-interactions", + "ui:siem/threat-intelligence", + "alerting:siem.notifications/siem/rule/get", + "alerting:siem.notifications/siem/rule/getRuleState", + "alerting:siem.notifications/siem/rule/getAlertSummary", + "alerting:siem.notifications/siem/rule/getExecutionLog", + "alerting:siem.notifications/siem/rule/getActionErrorLog", + "alerting:siem.notifications/siem/rule/find", + "alerting:siem.notifications/siem/rule/getRuleExecutionKPI", + "alerting:siem.notifications/siem/rule/getBackfill", + "alerting:siem.notifications/siem/rule/findBackfill", + "alerting:siem.esqlRule/siem/rule/get", + "alerting:siem.esqlRule/siem/rule/getRuleState", + "alerting:siem.esqlRule/siem/rule/getAlertSummary", + "alerting:siem.esqlRule/siem/rule/getExecutionLog", + "alerting:siem.esqlRule/siem/rule/getActionErrorLog", + "alerting:siem.esqlRule/siem/rule/find", + "alerting:siem.esqlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.esqlRule/siem/rule/getBackfill", + "alerting:siem.esqlRule/siem/rule/findBackfill", + "alerting:siem.eqlRule/siem/rule/get", + "alerting:siem.eqlRule/siem/rule/getRuleState", + "alerting:siem.eqlRule/siem/rule/getAlertSummary", + "alerting:siem.eqlRule/siem/rule/getExecutionLog", + "alerting:siem.eqlRule/siem/rule/getActionErrorLog", + "alerting:siem.eqlRule/siem/rule/find", + "alerting:siem.eqlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.eqlRule/siem/rule/getBackfill", + "alerting:siem.eqlRule/siem/rule/findBackfill", + "alerting:siem.indicatorRule/siem/rule/get", + "alerting:siem.indicatorRule/siem/rule/getRuleState", + "alerting:siem.indicatorRule/siem/rule/getAlertSummary", + "alerting:siem.indicatorRule/siem/rule/getExecutionLog", + "alerting:siem.indicatorRule/siem/rule/getActionErrorLog", + "alerting:siem.indicatorRule/siem/rule/find", + "alerting:siem.indicatorRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.indicatorRule/siem/rule/getBackfill", + "alerting:siem.indicatorRule/siem/rule/findBackfill", + "alerting:siem.mlRule/siem/rule/get", + "alerting:siem.mlRule/siem/rule/getRuleState", + "alerting:siem.mlRule/siem/rule/getAlertSummary", + "alerting:siem.mlRule/siem/rule/getExecutionLog", + "alerting:siem.mlRule/siem/rule/getActionErrorLog", + "alerting:siem.mlRule/siem/rule/find", + "alerting:siem.mlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.mlRule/siem/rule/getBackfill", + "alerting:siem.mlRule/siem/rule/findBackfill", + "alerting:siem.queryRule/siem/rule/get", + "alerting:siem.queryRule/siem/rule/getRuleState", + "alerting:siem.queryRule/siem/rule/getAlertSummary", + "alerting:siem.queryRule/siem/rule/getExecutionLog", + "alerting:siem.queryRule/siem/rule/getActionErrorLog", + "alerting:siem.queryRule/siem/rule/find", + "alerting:siem.queryRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.queryRule/siem/rule/getBackfill", + "alerting:siem.queryRule/siem/rule/findBackfill", + "alerting:siem.savedQueryRule/siem/rule/get", + "alerting:siem.savedQueryRule/siem/rule/getRuleState", + "alerting:siem.savedQueryRule/siem/rule/getAlertSummary", + "alerting:siem.savedQueryRule/siem/rule/getExecutionLog", + "alerting:siem.savedQueryRule/siem/rule/getActionErrorLog", + "alerting:siem.savedQueryRule/siem/rule/find", + "alerting:siem.savedQueryRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.savedQueryRule/siem/rule/getBackfill", + "alerting:siem.savedQueryRule/siem/rule/findBackfill", + "alerting:siem.thresholdRule/siem/rule/get", + "alerting:siem.thresholdRule/siem/rule/getRuleState", + "alerting:siem.thresholdRule/siem/rule/getAlertSummary", + "alerting:siem.thresholdRule/siem/rule/getExecutionLog", + "alerting:siem.thresholdRule/siem/rule/getActionErrorLog", + "alerting:siem.thresholdRule/siem/rule/find", + "alerting:siem.thresholdRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.thresholdRule/siem/rule/getBackfill", + "alerting:siem.thresholdRule/siem/rule/findBackfill", + "alerting:siem.newTermsRule/siem/rule/get", + "alerting:siem.newTermsRule/siem/rule/getRuleState", + "alerting:siem.newTermsRule/siem/rule/getAlertSummary", + "alerting:siem.newTermsRule/siem/rule/getExecutionLog", + "alerting:siem.newTermsRule/siem/rule/getActionErrorLog", + "alerting:siem.newTermsRule/siem/rule/find", + "alerting:siem.newTermsRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.newTermsRule/siem/rule/getBackfill", + "alerting:siem.newTermsRule/siem/rule/findBackfill", + "alerting:siem.notifications/siem/alert/get", + "alerting:siem.notifications/siem/alert/find", + "alerting:siem.notifications/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.notifications/siem/alert/getAlertSummary", + "alerting:siem.notifications/siem/alert/update", + "alerting:siem.esqlRule/siem/alert/get", + "alerting:siem.esqlRule/siem/alert/find", + "alerting:siem.esqlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.esqlRule/siem/alert/getAlertSummary", + "alerting:siem.esqlRule/siem/alert/update", + "alerting:siem.eqlRule/siem/alert/get", + "alerting:siem.eqlRule/siem/alert/find", + "alerting:siem.eqlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.eqlRule/siem/alert/getAlertSummary", + "alerting:siem.eqlRule/siem/alert/update", + "alerting:siem.indicatorRule/siem/alert/get", + "alerting:siem.indicatorRule/siem/alert/find", + "alerting:siem.indicatorRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.indicatorRule/siem/alert/getAlertSummary", + "alerting:siem.indicatorRule/siem/alert/update", + "alerting:siem.mlRule/siem/alert/get", + "alerting:siem.mlRule/siem/alert/find", + "alerting:siem.mlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.mlRule/siem/alert/getAlertSummary", + "alerting:siem.mlRule/siem/alert/update", + "alerting:siem.queryRule/siem/alert/get", + "alerting:siem.queryRule/siem/alert/find", + "alerting:siem.queryRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.queryRule/siem/alert/getAlertSummary", + "alerting:siem.queryRule/siem/alert/update", + "alerting:siem.savedQueryRule/siem/alert/get", + "alerting:siem.savedQueryRule/siem/alert/find", + "alerting:siem.savedQueryRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.savedQueryRule/siem/alert/getAlertSummary", + "alerting:siem.savedQueryRule/siem/alert/update", + "alerting:siem.thresholdRule/siem/alert/get", + "alerting:siem.thresholdRule/siem/alert/find", + "alerting:siem.thresholdRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.thresholdRule/siem/alert/getAlertSummary", + "alerting:siem.thresholdRule/siem/alert/update", + "alerting:siem.newTermsRule/siem/alert/get", + "alerting:siem.newTermsRule/siem/alert/find", + "alerting:siem.newTermsRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.newTermsRule/siem/alert/getAlertSummary", + "alerting:siem.newTermsRule/siem/alert/update", + "app:discover", + "ui:catalogue/discover", + "ui:navLinks/discover", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "ui:discover/show", + "ui:discover/createShortUrl", + "api:bulkGetUserProfiles", + "app:dashboards", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "ui:dashboard/show", + "ui:dashboard/createShortUrl", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "ui:visualize/show", + "ui:visualize/createShortUrl", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "ui:maps/show", + ], + "policy_management_all": Array [ + "login:", + "api:securitySolution-writePolicyManagement", + "api:securitySolution-readPolicyManagement", + "saved_object:policy-settings-protection-updates-note/bulk_get", + "saved_object:policy-settings-protection-updates-note/get", + "saved_object:policy-settings-protection-updates-note/find", + "saved_object:policy-settings-protection-updates-note/open_point_in_time", + "saved_object:policy-settings-protection-updates-note/close_point_in_time", + "saved_object:policy-settings-protection-updates-note/create", + "saved_object:policy-settings-protection-updates-note/bulk_create", + "saved_object:policy-settings-protection-updates-note/update", + "saved_object:policy-settings-protection-updates-note/bulk_update", + "saved_object:policy-settings-protection-updates-note/delete", + "saved_object:policy-settings-protection-updates-note/bulk_delete", + "saved_object:policy-settings-protection-updates-note/share_to_space", + "ui:siem/writePolicyManagement", + "ui:siem/readPolicyManagement", + ], + "policy_management_read": Array [ + "login:", + "api:securitySolution-readPolicyManagement", + "saved_object:policy-settings-protection-updates-note/bulk_get", + "saved_object:policy-settings-protection-updates-note/get", + "saved_object:policy-settings-protection-updates-note/find", + "saved_object:policy-settings-protection-updates-note/open_point_in_time", + "saved_object:policy-settings-protection-updates-note/close_point_in_time", + "ui:siem/readPolicyManagement", + ], + "process_operations_all": Array [ + "login:", + "api:securitySolution-writeProcessOperations", + "ui:siem/writeProcessOperations", + ], + "read": Array [ + "login:", + "api:securitySolution", + "api:lists-read", + "api:rac", + "api:cloud-security-posture-read", + "api:cloud-defend-read", + "api:securitySolution-entity-analytics", + "api:securitySolution-threat-intelligence", + "api:securitySolution-showEndpointExceptions", + "app:securitySolution", + "app:csp", + "app:cloudDefend", + "app:kibana", + "ui:catalogue/securitySolution", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/securitySolution", + "ui:navLinks/csp", + "ui:navLinks/cloudDefend", + "ui:navLinks/kibana", + "saved_object:exception-list/bulk_get", + "saved_object:exception-list/get", + "saved_object:exception-list/find", + "saved_object:exception-list/open_point_in_time", + "saved_object:exception-list/close_point_in_time", + "saved_object:exception-list-agnostic/bulk_get", + "saved_object:exception-list-agnostic/get", + "saved_object:exception-list-agnostic/find", + "saved_object:exception-list-agnostic/open_point_in_time", + "saved_object:exception-list-agnostic/close_point_in_time", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:siem-ui-timeline-note/bulk_get", + "saved_object:siem-ui-timeline-note/get", + "saved_object:siem-ui-timeline-note/find", + "saved_object:siem-ui-timeline-note/open_point_in_time", + "saved_object:siem-ui-timeline-note/close_point_in_time", + "saved_object:siem-ui-timeline-pinned-event/bulk_get", + "saved_object:siem-ui-timeline-pinned-event/get", + "saved_object:siem-ui-timeline-pinned-event/find", + "saved_object:siem-ui-timeline-pinned-event/open_point_in_time", + "saved_object:siem-ui-timeline-pinned-event/close_point_in_time", + "saved_object:siem-detection-engine-rule-actions/bulk_get", + "saved_object:siem-detection-engine-rule-actions/get", + "saved_object:siem-detection-engine-rule-actions/find", + "saved_object:siem-detection-engine-rule-actions/open_point_in_time", + "saved_object:siem-detection-engine-rule-actions/close_point_in_time", + "saved_object:security-rule/bulk_get", + "saved_object:security-rule/get", + "saved_object:security-rule/find", + "saved_object:security-rule/open_point_in_time", + "saved_object:security-rule/close_point_in_time", + "saved_object:siem-ui-timeline/bulk_get", + "saved_object:siem-ui-timeline/get", + "saved_object:siem-ui-timeline/find", + "saved_object:siem-ui-timeline/open_point_in_time", + "saved_object:siem-ui-timeline/close_point_in_time", + "saved_object:endpoint:user-artifact-manifest/bulk_get", + "saved_object:endpoint:user-artifact-manifest/get", + "saved_object:endpoint:user-artifact-manifest/find", + "saved_object:endpoint:user-artifact-manifest/open_point_in_time", + "saved_object:endpoint:user-artifact-manifest/close_point_in_time", + "saved_object:endpoint:unified-user-artifact-manifest/bulk_get", + "saved_object:endpoint:unified-user-artifact-manifest/get", + "saved_object:endpoint:unified-user-artifact-manifest/find", + "saved_object:endpoint:unified-user-artifact-manifest/open_point_in_time", + "saved_object:endpoint:unified-user-artifact-manifest/close_point_in_time", + "saved_object:security-solution-signals-migration/bulk_get", + "saved_object:security-solution-signals-migration/get", + "saved_object:security-solution-signals-migration/find", + "saved_object:security-solution-signals-migration/open_point_in_time", + "saved_object:security-solution-signals-migration/close_point_in_time", + "saved_object:risk-engine-configuration/bulk_get", + "saved_object:risk-engine-configuration/get", + "saved_object:risk-engine-configuration/find", + "saved_object:risk-engine-configuration/open_point_in_time", + "saved_object:risk-engine-configuration/close_point_in_time", + "saved_object:policy-settings-protection-updates-note/bulk_get", + "saved_object:policy-settings-protection-updates-note/get", + "saved_object:policy-settings-protection-updates-note/find", + "saved_object:policy-settings-protection-updates-note/open_point_in_time", + "saved_object:policy-settings-protection-updates-note/close_point_in_time", + "saved_object:csp_rule/bulk_get", + "saved_object:csp_rule/get", + "saved_object:csp_rule/find", + "saved_object:csp_rule/open_point_in_time", + "saved_object:csp_rule/close_point_in_time", + "saved_object:cloud-security-posture-settings/bulk_get", + "saved_object:cloud-security-posture-settings/get", + "saved_object:cloud-security-posture-settings/find", + "saved_object:cloud-security-posture-settings/open_point_in_time", + "saved_object:cloud-security-posture-settings/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:siem/show", + "ui:siem/entity-analytics", + "ui:siem/investigation-guide", + "ui:siem/investigation-guide-interactions", + "ui:siem/threat-intelligence", + "ui:siem/showEndpointExceptions", + "alerting:siem.notifications/siem/rule/get", + "alerting:siem.notifications/siem/rule/getRuleState", + "alerting:siem.notifications/siem/rule/getAlertSummary", + "alerting:siem.notifications/siem/rule/getExecutionLog", + "alerting:siem.notifications/siem/rule/getActionErrorLog", + "alerting:siem.notifications/siem/rule/find", + "alerting:siem.notifications/siem/rule/getRuleExecutionKPI", + "alerting:siem.notifications/siem/rule/getBackfill", + "alerting:siem.notifications/siem/rule/findBackfill", + "alerting:siem.esqlRule/siem/rule/get", + "alerting:siem.esqlRule/siem/rule/getRuleState", + "alerting:siem.esqlRule/siem/rule/getAlertSummary", + "alerting:siem.esqlRule/siem/rule/getExecutionLog", + "alerting:siem.esqlRule/siem/rule/getActionErrorLog", + "alerting:siem.esqlRule/siem/rule/find", + "alerting:siem.esqlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.esqlRule/siem/rule/getBackfill", + "alerting:siem.esqlRule/siem/rule/findBackfill", + "alerting:siem.eqlRule/siem/rule/get", + "alerting:siem.eqlRule/siem/rule/getRuleState", + "alerting:siem.eqlRule/siem/rule/getAlertSummary", + "alerting:siem.eqlRule/siem/rule/getExecutionLog", + "alerting:siem.eqlRule/siem/rule/getActionErrorLog", + "alerting:siem.eqlRule/siem/rule/find", + "alerting:siem.eqlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.eqlRule/siem/rule/getBackfill", + "alerting:siem.eqlRule/siem/rule/findBackfill", + "alerting:siem.indicatorRule/siem/rule/get", + "alerting:siem.indicatorRule/siem/rule/getRuleState", + "alerting:siem.indicatorRule/siem/rule/getAlertSummary", + "alerting:siem.indicatorRule/siem/rule/getExecutionLog", + "alerting:siem.indicatorRule/siem/rule/getActionErrorLog", + "alerting:siem.indicatorRule/siem/rule/find", + "alerting:siem.indicatorRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.indicatorRule/siem/rule/getBackfill", + "alerting:siem.indicatorRule/siem/rule/findBackfill", + "alerting:siem.mlRule/siem/rule/get", + "alerting:siem.mlRule/siem/rule/getRuleState", + "alerting:siem.mlRule/siem/rule/getAlertSummary", + "alerting:siem.mlRule/siem/rule/getExecutionLog", + "alerting:siem.mlRule/siem/rule/getActionErrorLog", + "alerting:siem.mlRule/siem/rule/find", + "alerting:siem.mlRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.mlRule/siem/rule/getBackfill", + "alerting:siem.mlRule/siem/rule/findBackfill", + "alerting:siem.queryRule/siem/rule/get", + "alerting:siem.queryRule/siem/rule/getRuleState", + "alerting:siem.queryRule/siem/rule/getAlertSummary", + "alerting:siem.queryRule/siem/rule/getExecutionLog", + "alerting:siem.queryRule/siem/rule/getActionErrorLog", + "alerting:siem.queryRule/siem/rule/find", + "alerting:siem.queryRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.queryRule/siem/rule/getBackfill", + "alerting:siem.queryRule/siem/rule/findBackfill", + "alerting:siem.savedQueryRule/siem/rule/get", + "alerting:siem.savedQueryRule/siem/rule/getRuleState", + "alerting:siem.savedQueryRule/siem/rule/getAlertSummary", + "alerting:siem.savedQueryRule/siem/rule/getExecutionLog", + "alerting:siem.savedQueryRule/siem/rule/getActionErrorLog", + "alerting:siem.savedQueryRule/siem/rule/find", + "alerting:siem.savedQueryRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.savedQueryRule/siem/rule/getBackfill", + "alerting:siem.savedQueryRule/siem/rule/findBackfill", + "alerting:siem.thresholdRule/siem/rule/get", + "alerting:siem.thresholdRule/siem/rule/getRuleState", + "alerting:siem.thresholdRule/siem/rule/getAlertSummary", + "alerting:siem.thresholdRule/siem/rule/getExecutionLog", + "alerting:siem.thresholdRule/siem/rule/getActionErrorLog", + "alerting:siem.thresholdRule/siem/rule/find", + "alerting:siem.thresholdRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.thresholdRule/siem/rule/getBackfill", + "alerting:siem.thresholdRule/siem/rule/findBackfill", + "alerting:siem.newTermsRule/siem/rule/get", + "alerting:siem.newTermsRule/siem/rule/getRuleState", + "alerting:siem.newTermsRule/siem/rule/getAlertSummary", + "alerting:siem.newTermsRule/siem/rule/getExecutionLog", + "alerting:siem.newTermsRule/siem/rule/getActionErrorLog", + "alerting:siem.newTermsRule/siem/rule/find", + "alerting:siem.newTermsRule/siem/rule/getRuleExecutionKPI", + "alerting:siem.newTermsRule/siem/rule/getBackfill", + "alerting:siem.newTermsRule/siem/rule/findBackfill", + "alerting:siem.notifications/siem/alert/get", + "alerting:siem.notifications/siem/alert/find", + "alerting:siem.notifications/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.notifications/siem/alert/getAlertSummary", + "alerting:siem.notifications/siem/alert/update", + "alerting:siem.esqlRule/siem/alert/get", + "alerting:siem.esqlRule/siem/alert/find", + "alerting:siem.esqlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.esqlRule/siem/alert/getAlertSummary", + "alerting:siem.esqlRule/siem/alert/update", + "alerting:siem.eqlRule/siem/alert/get", + "alerting:siem.eqlRule/siem/alert/find", + "alerting:siem.eqlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.eqlRule/siem/alert/getAlertSummary", + "alerting:siem.eqlRule/siem/alert/update", + "alerting:siem.indicatorRule/siem/alert/get", + "alerting:siem.indicatorRule/siem/alert/find", + "alerting:siem.indicatorRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.indicatorRule/siem/alert/getAlertSummary", + "alerting:siem.indicatorRule/siem/alert/update", + "alerting:siem.mlRule/siem/alert/get", + "alerting:siem.mlRule/siem/alert/find", + "alerting:siem.mlRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.mlRule/siem/alert/getAlertSummary", + "alerting:siem.mlRule/siem/alert/update", + "alerting:siem.queryRule/siem/alert/get", + "alerting:siem.queryRule/siem/alert/find", + "alerting:siem.queryRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.queryRule/siem/alert/getAlertSummary", + "alerting:siem.queryRule/siem/alert/update", + "alerting:siem.savedQueryRule/siem/alert/get", + "alerting:siem.savedQueryRule/siem/alert/find", + "alerting:siem.savedQueryRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.savedQueryRule/siem/alert/getAlertSummary", + "alerting:siem.savedQueryRule/siem/alert/update", + "alerting:siem.thresholdRule/siem/alert/get", + "alerting:siem.thresholdRule/siem/alert/find", + "alerting:siem.thresholdRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.thresholdRule/siem/alert/getAlertSummary", + "alerting:siem.thresholdRule/siem/alert/update", + "alerting:siem.newTermsRule/siem/alert/get", + "alerting:siem.newTermsRule/siem/alert/find", + "alerting:siem.newTermsRule/siem/alert/getAuthorizedAlertsIndices", + "alerting:siem.newTermsRule/siem/alert/getAlertSummary", + "alerting:siem.newTermsRule/siem/alert/update", + "app:discover", + "ui:catalogue/discover", + "ui:navLinks/discover", + "saved_object:url/create", + "saved_object:url/bulk_create", + "saved_object:url/update", + "saved_object:url/bulk_update", + "saved_object:url/delete", + "saved_object:url/bulk_delete", + "saved_object:url/share_to_space", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "ui:discover/show", + "ui:discover/createShortUrl", + "api:bulkGetUserProfiles", + "app:dashboards", + "ui:catalogue/dashboard", + "ui:navLinks/dashboards", + "saved_object:visualization/bulk_get", + "saved_object:visualization/get", + "saved_object:visualization/find", + "saved_object:visualization/open_point_in_time", + "saved_object:visualization/close_point_in_time", + "saved_object:canvas-workpad/bulk_get", + "saved_object:canvas-workpad/get", + "saved_object:canvas-workpad/find", + "saved_object:canvas-workpad/open_point_in_time", + "saved_object:canvas-workpad/close_point_in_time", + "saved_object:lens/bulk_get", + "saved_object:lens/get", + "saved_object:lens/find", + "saved_object:lens/open_point_in_time", + "saved_object:lens/close_point_in_time", + "saved_object:links/bulk_get", + "saved_object:links/get", + "saved_object:links/find", + "saved_object:links/open_point_in_time", + "saved_object:links/close_point_in_time", + "saved_object:map/bulk_get", + "saved_object:map/get", + "saved_object:map/find", + "saved_object:map/open_point_in_time", + "saved_object:map/close_point_in_time", + "saved_object:dashboard/bulk_get", + "saved_object:dashboard/get", + "saved_object:dashboard/find", + "saved_object:dashboard/open_point_in_time", + "saved_object:dashboard/close_point_in_time", + "saved_object:tag/bulk_get", + "saved_object:tag/get", + "saved_object:tag/find", + "saved_object:tag/open_point_in_time", + "saved_object:tag/close_point_in_time", + "ui:dashboard/show", + "ui:dashboard/createShortUrl", + "app:visualize", + "app:lens", + "ui:catalogue/visualize", + "ui:navLinks/visualize", + "ui:navLinks/lens", + "ui:visualize/show", + "ui:visualize/createShortUrl", + "app:maps", + "ui:catalogue/maps", + "ui:navLinks/maps", + "ui:maps/show", + ], + "trusted_applications_all": Array [ + "login:", + "api:lists-all", + "api:lists-read", + "api:lists-summary", + "api:securitySolution-writeTrustedApplications", + "api:securitySolution-readTrustedApplications", + "saved_object:exception-list-agnostic/bulk_get", + "saved_object:exception-list-agnostic/get", + "saved_object:exception-list-agnostic/find", + "saved_object:exception-list-agnostic/open_point_in_time", + "saved_object:exception-list-agnostic/close_point_in_time", + "saved_object:exception-list-agnostic/create", + "saved_object:exception-list-agnostic/bulk_create", + "saved_object:exception-list-agnostic/update", + "saved_object:exception-list-agnostic/bulk_update", + "saved_object:exception-list-agnostic/delete", + "saved_object:exception-list-agnostic/bulk_delete", + "saved_object:exception-list-agnostic/share_to_space", + "ui:siem/writeTrustedApplications", + "ui:siem/readTrustedApplications", + ], + "trusted_applications_read": Array [ + "login:", + "api:lists-read", + "api:lists-summary", + "api:securitySolution-readTrustedApplications", + "ui:siem/readTrustedApplications", + ], + }, + } + `); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/security/platform_security/index.ts b/x-pack/test_serverless/api_integration/test_suites/security/platform_security/index.ts new file mode 100644 index 0000000000000..5271f15b683f1 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/security/platform_security/index.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. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Platform security APIs', function () { + loadTestFile(require.resolve('./authorization')); + }); +} diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index 5dff8ab3431fd..e80bebb0e90ae 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -101,6 +101,7 @@ "@kbn/dataset-quality-plugin", "@kbn/alerting-comparators", "@kbn/search-types", - "@kbn/reporting-server" + "@kbn/reporting-server", + "@kbn/features-plugin" ] } From 556531b33336dad8ce502b36e119b90c7825b44a Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Thu, 6 Jun 2024 06:56:33 -0700 Subject: [PATCH 16/87] Fix sort field error message for last value (#184883) This PR fixes a minor bug on the **Last Value** editor config in which the **Sort by date field** was always considered invalid. --- .../definitions/last_value.test.tsx | 68 +++++++++++++++++++ .../operations/definitions/last_value.tsx | 11 ++- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.test.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.test.tsx index 61748339d2a72..2beefab2f1439 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.test.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.test.tsx @@ -21,6 +21,7 @@ import type { FormBasedLayer } from '../../types'; import { TermsIndexPatternColumn } from './terms'; import { EuiSwitch, EuiSwitchEvent } from '@elastic/eui'; import { buildExpression, parseExpression } from '@kbn/expressions-plugin/common'; +import { FormRow } from './shared_components'; const uiSettingsMock = {} as IUiSettingsClient; @@ -877,6 +878,7 @@ describe('last_value', () => { expect(new Harness(instance).showArrayValuesSwitchDisabled).toBeTruthy(); }); + it('should not display an array for the last value if the column is referenced', () => { const updateLayerSpy = jest.fn(); const instance = shallow( @@ -892,6 +894,72 @@ describe('last_value', () => { expect(new Harness(instance).arrayValuesSwitchNotExisiting).toBeTruthy(); }); + + it('should show valid sort field for date field', () => { + const instance = shallow( + + ); + + expect(instance.find(FormRow).prop('isInvalid')).toBe(false); + }); + + it('should show invalid sort field for missing field', () => { + const instance = shallow( + + ); + + expect(instance.find(FormRow).prop('isInvalid')).toBe(true); + }); + + it('should show invalid sort field for non-date field', () => { + const instance = shallow( + + ); + + expect(instance.find(FormRow).prop('isInvalid')).toBe(true); + }); }); }); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx index b508534a19800..337ec8052d0ed 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx @@ -69,7 +69,7 @@ const supportedTypes = new Set([ 'date_range', ]); -function getInvalidSortFieldMessage( +function getInvalidSortFieldMessages( sortField: string, columnId: string, indexPattern?: IndexPattern @@ -226,7 +226,7 @@ export const lastValueOperation: OperationDefinition< const column = layer.columns[columnId] as LastValueIndexPatternColumn; return [ ...getInvalidFieldMessage(layer, columnId, indexPattern), - ...getInvalidSortFieldMessage(column.params.sortField, columnId, indexPattern), + ...getInvalidSortFieldMessages(column.params.sortField, columnId, indexPattern), ...getColumnReducedTimeRangeError(layer, columnId, indexPattern), ]; }, @@ -331,11 +331,8 @@ export const lastValueOperation: OperationDefinition< }); const dateFields = getDateFields(indexPattern); - const isSortFieldInvalid = !!getInvalidSortFieldMessage( - currentColumn.params.sortField, - '', - indexPattern - ); + const isSortFieldInvalid = + getInvalidSortFieldMessages(currentColumn.params.sortField, '', indexPattern).length > 0; const usingTopValues = Object.keys(layer.columns).some( (_columnId) => layer.columns[_columnId].operationType === 'terms' From 318f1532904fd9f14cc9291d3813278f005bd5ee Mon Sep 17 00:00:00 2001 From: Jill Guyonnet Date: Thu, 6 Jun 2024 15:18:29 +0100 Subject: [PATCH 17/87] [IUI] Add unprivilieged agent install instruction (#184845) ## Summary Closes https://github.com/elastic/ingest-dev/issues/3356 This PR adds a sentence to the `Add agent` flyout to instruct how to install an unprivileged Elastic Agent. Screenshot 2024-06-05 at 16 53 13 --- .../install_section.tsx | 2 ++ .../unprivileged_info.tsx | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 x-pack/plugins/fleet/public/components/enrollment_instructions/unprivileged_info.tsx diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/install_section.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/install_section.tsx index 372f81ca47f96..b94291e48663a 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/install_section.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/install_section.tsx @@ -15,6 +15,7 @@ import type { K8sMode, CloudSecurityIntegration } from '../agent_enrollment_flyo import { PlatformSelector } from '../platform_selector'; import { RootPrivilegesCallout } from './root_privileges_callout'; +import { UnprivilegedInfo } from './unprivileged_info'; interface Props { installCommand: CommandsByPlatform; @@ -43,6 +44,7 @@ export const InstallSection: React.FunctionComponent = ({ <> + { + return ( + <> + +

+ --unprivileged, + command: sudo ./elastic-agent, + }} + /> +

+
+ + + ); +}; From 15424370e167f7377e3b1a93fd40e03c4639e95e Mon Sep 17 00:00:00 2001 From: elena-shostak <165678770+elena-shostak@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:23:56 +0200 Subject: [PATCH 18/87] [Spaces] Support for query params in next route when entering space (#184858) ## Summary Added support for query params in next route when entering space. ### Checklist - [x] [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 ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) __Fixes: https://github.com/elastic/kibana/issues/184857__ --- x-pack/plugins/spaces/server/routes/views/index.test.ts | 7 +++++++ x-pack/plugins/spaces/server/routes/views/index.ts | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/spaces/server/routes/views/index.test.ts b/x-pack/plugins/spaces/server/routes/views/index.test.ts index 6c035a5694fe4..ad4cd61029af1 100644 --- a/x-pack/plugins/spaces/server/routes/views/index.test.ts +++ b/x-pack/plugins/spaces/server/routes/views/index.test.ts @@ -198,6 +198,13 @@ describe('Enter Space view routes', () => { }, expectedLocation: '/mock-server-basepath/app/management/kibana/home', }, + { + query: { + next: '/app/management/kibana/objects?initialQuery=type:(visualization)', + }, + expectedLocation: + '/mock-server-basepath/app/management/kibana/objects?initialQuery=type:(visualization)', + }, ]) { const request = httpServerMock.createKibanaRequest({ query, diff --git a/x-pack/plugins/spaces/server/routes/views/index.ts b/x-pack/plugins/spaces/server/routes/views/index.ts index 73fa47338dd76..495e0132059be 100644 --- a/x-pack/plugins/spaces/server/routes/views/index.ts +++ b/x-pack/plugins/spaces/server/routes/views/index.ts @@ -42,11 +42,11 @@ export function initSpacesViewsRoutes(deps: ViewRouteDeps) { const route = nextCandidateRoute === '/' ? defaultRoute : nextCandidateRoute; // need to get reed of ../../ to make sure we will not be out of space basePath - const normalizedRoute = new URL(route, 'https://localhost').pathname; + const normalizedRoute = new URL(route, 'https://localhost'); return response.redirected({ headers: { - location: `${basePath}${normalizedRoute}`, + location: `${basePath}${normalizedRoute.pathname}${normalizedRoute.search}`, }, }); } catch (e) { From 620359f893912189cc9e4d51d635879778b55d6a Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Thu, 6 Jun 2024 16:36:02 +0200 Subject: [PATCH 19/87] [APM] Trace sample performance improvements (#183802) Fixes #178985 ## Summary This PR changes the frontend logic to render the trace waterfall component. Instead of recursively rendering transactions/spans and their child transactions/spans, which causes high memory usage depending on the amount of data/how complex the trace to be rendered is, it now uses tree data structure and BFS/DFS algorithms. Besides that, the trace sample component can render a very long list. To avoid rendering too many elements in the DOM, this PR changes it to use a virtual list ### Memory consumption 15-minutes worth of data | before | after | |-------|-------| |image|image| 30-minutes worth of data | before | after | |-------|-------| |image|image| 1-hour worth of data | before | after | |-------|-------| |image|image| ### Extra Sticky header fix https://github.com/elastic/kibana/assets/2767137/632485ee-80c5-486d-aaa2-c34047b9c11e ### How to test The best way to test is to connect to an oblt cluster - Navigate to APM > Dependencies - Go into `cartService` - Click on `Operations` tab and click on `POST /nodejs/addToCart` operation. - Select different date ranges and services ### For reviewers There is a problem with positioning the trace elements in the grid when rendering data for large date ranges https://github.com/elastic/kibana/issues/178985#issuecomment-2137480777. This won't be addressed in this PR --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../src/lib/apm/apm_error.ts | 11 +- .../src/lib/apm/mobile_device.ts | 4 +- .../src/lib/utils/generate_id.ts | 31 +- .../test/scenarios/01_simple_trace.test.ts | 67 ++- .../01_simple_trace.test.ts.snap | 180 ++++---- .../cypress/e2e/errors/error_details.cy.ts | 4 +- .../large_traces_in_waterfall.cy.ts | 8 +- .../index.tsx | 58 ++- .../trace_explorer_waterfall.tsx | 93 ++-- .../distribution/index.tsx | 28 +- .../waterfall_with_summary/index.tsx | 20 +- .../waterfall/accordion_waterfall.tsx | 228 +++++---- .../waterfall/context/use_waterfall.tsx | 13 + .../waterfall/context/waterfall_context.tsx | 118 +++++ .../waterfall_container/waterfall/index.tsx | 134 +++--- .../waterfall_helpers.test.ts | 436 +++++++++++++----- .../waterfall_helpers/waterfall_helpers.ts | 203 +++++++- .../waterfall/waterfall_item.tsx | 4 +- .../__snapshots__/timeline.test.tsx.snap | 354 +++++++++++++- .../shared/charts/timeline/index.tsx | 54 ++- .../shared/charts/timeline/plot_utils.ts | 3 - .../shared/charts/timeline/timeline.test.tsx | 25 +- .../shared/charts/timeline/timeline_axis.tsx | 7 +- .../shared/charts/timeline/vertical_lines.tsx | 10 +- 24 files changed, 1591 insertions(+), 502 deletions(-) create mode 100644 x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/context/use_waterfall.tsx create mode 100644 x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/context/waterfall_context.tsx diff --git a/packages/kbn-apm-synthtrace-client/src/lib/apm/apm_error.ts b/packages/kbn-apm-synthtrace-client/src/lib/apm/apm_error.ts index 216397f1e1b40..250375623dfc3 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/apm/apm_error.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/apm/apm_error.ts @@ -8,7 +8,7 @@ import { ApmFields } from './apm_fields'; import { Serializable } from '../serializable'; -import { generateLongId, generateShortId } from '../utils/generate_id'; +import { generateLongIdWithSeed, generateShortId, generateLongId } from '../utils/generate_id'; export class ApmError extends Serializable { constructor(fields: ApmFields) { @@ -21,10 +21,13 @@ export class ApmError extends Serializable { } serialize() { + const errorMessage = + this.fields['error.grouping_name'] || this.fields['error.exception']?.[0]?.message; + const [data] = super.serialize(); - data['error.grouping_key'] = generateLongId( - this.fields['error.grouping_name'] || this.fields['error.exception']?.[0]?.message - ); + data['error.grouping_key'] = errorMessage + ? generateLongIdWithSeed(errorMessage) + : generateLongId(); return [data]; } diff --git a/packages/kbn-apm-synthtrace-client/src/lib/apm/mobile_device.ts b/packages/kbn-apm-synthtrace-client/src/lib/apm/mobile_device.ts index b0ea0aea4663e..205cc7d07f14f 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/apm/mobile_device.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/apm/mobile_device.ts @@ -11,7 +11,7 @@ import { Span } from './span'; import { Transaction } from './transaction'; import { Event } from './event'; import { ApmApplicationMetricFields, ApmFields, GeoLocation, SpanParams } from './apm_fields'; -import { generateLongId } from '../utils/generate_id'; +import { generateLongIdWithSeed, generateLongId } from '../utils/generate_id'; import { Metricset } from './metricset'; import { ApmError } from './apm_error'; @@ -259,7 +259,7 @@ export class MobileDevice extends Entity { return new ApmError({ ...this.fields, 'error.type': 'crash', - 'error.id': generateLongId(message), + 'error.id': generateLongIdWithSeed(message), 'error.exception': [{ message, ...{ type: 'crash' } }], 'error.grouping_name': groupingName || message, }); diff --git a/packages/kbn-apm-synthtrace-client/src/lib/utils/generate_id.ts b/packages/kbn-apm-synthtrace-client/src/lib/utils/generate_id.ts index c65c2843ddd3b..6815b79ef5cf8 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/utils/generate_id.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/utils/generate_id.ts @@ -7,16 +7,33 @@ */ let seq = 0; +const pid = String(process.pid); -function generateId(seed?: string, length: number = 32) { - const str = seed ?? String(seq++); - return str.padStart(length, '0'); +const LONG_ID_LENGTH = 32; +const SHORT_ID_LENGTH = 16; + +function generateId(length: number = LONG_ID_LENGTH) { + const id = String(seq++); + const generatedId = pid + id.padStart(length - pid.length, '0'); + if (generatedId.length > length) { + throw new Error(`generated id is longer than ${length} characters: ${generatedId.length}`); + } + + return generatedId; +} + +function generateIdWithSeed(seed: string, length: number = LONG_ID_LENGTH) { + return seed?.padStart(length, '0'); +} + +export function generateShortId() { + return generateId(SHORT_ID_LENGTH); } -export function generateShortId(seed?: string) { - return generateId(seed, 16); +export function generateLongId() { + return generateId(LONG_ID_LENGTH); } -export function generateLongId(seed?: string) { - return generateId(seed, 32); +export function generateLongIdWithSeed(seed: string) { + return generateIdWithSeed(seed, LONG_ID_LENGTH); } diff --git a/packages/kbn-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts b/packages/kbn-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts index 5c12116163721..df512cc6a8a4f 100644 --- a/packages/kbn-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts +++ b/packages/kbn-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts @@ -48,7 +48,24 @@ describe('simple trace', () => { // TODO this is not entirely factual, since id's are generated of a global sequence number it('generates the same data every time', () => { - expect(events).toMatchSnapshot(); + expect(events).toMatchSnapshot( + events.map((event) => { + const matchers: Record = {}; + if (event['transaction.id']) { + matchers['transaction.id'] = expect.any(String); + } + if (event['trace.id']) { + matchers['trace.id'] = expect.any(String); + } + if (event['span.id']) { + matchers['span.id'] = expect.any(String); + } + if (event['parent.id']) { + matchers['parent.id'] = expect.any(String); + } + return matchers; + }) + ); }); it('generates 15 transaction events', () => { @@ -83,9 +100,9 @@ describe('simple trace', () => { 'service.name': 'opbeans-java', 'service.node.name': 'instance-1', 'timestamp.us': 1609459200000000, - 'trace.id': '00000000000000000000000000000241', + 'trace.id': expect.stringContaining('00000000000000000000000241'), 'transaction.duration.us': 1000000, - 'transaction.id': '0000000000000240', + 'transaction.id': expect.stringContaining('0000000240'), 'transaction.name': 'GET /api/product/list', 'transaction.type': 'request', 'transaction.sampled': true, @@ -95,26 +112,28 @@ describe('simple trace', () => { it('outputs span events', () => { const [, span] = events; - expect(span).toEqual({ - '@timestamp': 1609459200050, - 'agent.name': 'java', - 'container.id': 'instance-1', - 'event.outcome': 'success', - 'host.name': 'instance-1', - 'parent.id': '0000000000000300', - 'processor.event': 'span', - 'processor.name': 'transaction', - 'service.environment': 'production', - 'service.name': 'opbeans-java', - 'service.node.name': 'instance-1', - 'span.duration.us': 900000, - 'span.id': '0000000000000302', - 'span.name': 'GET apm-*/_search', - 'span.subtype': 'elasticsearch', - 'span.type': 'db', - 'timestamp.us': 1609459200050000, - 'trace.id': '00000000000000000000000000000301', - 'transaction.id': '0000000000000300', - }); + expect(span).toEqual( + expect.objectContaining({ + '@timestamp': 1609459200050, + 'agent.name': 'java', + 'container.id': 'instance-1', + 'event.outcome': 'success', + 'host.name': 'instance-1', + 'parent.id': expect.stringContaining('0000000300'), + 'processor.event': 'span', + 'processor.name': 'transaction', + 'service.environment': 'production', + 'service.name': 'opbeans-java', + 'service.node.name': 'instance-1', + 'span.duration.us': 900000, + 'span.id': expect.stringContaining('0000000302'), + 'span.name': 'GET apm-*/_search', + 'span.subtype': 'elasticsearch', + 'span.type': 'db', + 'timestamp.us': 1609459200050000, + 'trace.id': expect.stringContaining('00000000000000000000000301'), + 'transaction.id': expect.stringContaining('0000000300'), + }) + ); }); }); diff --git a/packages/kbn-apm-synthtrace/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap b/packages/kbn-apm-synthtrace/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap index 15883c2711f43..f318942f397b3 100644 --- a/packages/kbn-apm-synthtrace/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap +++ b/packages/kbn-apm-synthtrace/src/test/scenarios/__snapshots__/01_simple_trace.test.ts.snap @@ -14,9 +14,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459200000000, - "trace.id": "00000000000000000000000000000001", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000000", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -27,20 +27,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000000", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000002", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459200050000, - "trace.id": "00000000000000000000000000000001", - "transaction.id": "0000000000000000", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459200000, @@ -95,9 +95,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459260000000, - "trace.id": "00000000000000000000000000000005", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000004", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -108,20 +108,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000004", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000006", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459260050000, - "trace.id": "00000000000000000000000000000005", - "transaction.id": "0000000000000004", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459260000, @@ -176,9 +176,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459320000000, - "trace.id": "00000000000000000000000000000009", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000008", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -189,20 +189,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000008", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000010", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459320050000, - "trace.id": "00000000000000000000000000000009", - "transaction.id": "0000000000000008", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459320000, @@ -257,9 +257,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459380000000, - "trace.id": "00000000000000000000000000000013", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000012", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -270,20 +270,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000012", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000014", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459380050000, - "trace.id": "00000000000000000000000000000013", - "transaction.id": "0000000000000012", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459380000, @@ -338,9 +338,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459440000000, - "trace.id": "00000000000000000000000000000017", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000016", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -351,20 +351,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000016", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000018", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459440050000, - "trace.id": "00000000000000000000000000000017", - "transaction.id": "0000000000000016", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459440000, @@ -419,9 +419,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459500000000, - "trace.id": "00000000000000000000000000000021", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000020", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -432,20 +432,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000020", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000022", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459500050000, - "trace.id": "00000000000000000000000000000021", - "transaction.id": "0000000000000020", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459500000, @@ -500,9 +500,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459560000000, - "trace.id": "00000000000000000000000000000025", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000024", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -513,20 +513,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000024", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000026", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459560050000, - "trace.id": "00000000000000000000000000000025", - "transaction.id": "0000000000000024", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459560000, @@ -581,9 +581,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459620000000, - "trace.id": "00000000000000000000000000000029", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000028", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -594,20 +594,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000028", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000030", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459620050000, - "trace.id": "00000000000000000000000000000029", - "transaction.id": "0000000000000028", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459620000, @@ -662,9 +662,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459680000000, - "trace.id": "00000000000000000000000000000033", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000032", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -675,20 +675,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000032", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000034", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459680050000, - "trace.id": "00000000000000000000000000000033", - "transaction.id": "0000000000000032", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459680000, @@ -743,9 +743,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459740000000, - "trace.id": "00000000000000000000000000000037", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000036", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -756,20 +756,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000036", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000038", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459740050000, - "trace.id": "00000000000000000000000000000037", - "transaction.id": "0000000000000036", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459740000, @@ -824,9 +824,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459800000000, - "trace.id": "00000000000000000000000000000041", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000040", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -837,20 +837,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000040", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000042", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459800050000, - "trace.id": "00000000000000000000000000000041", - "transaction.id": "0000000000000040", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459800000, @@ -905,9 +905,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459860000000, - "trace.id": "00000000000000000000000000000045", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000044", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -918,20 +918,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000044", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000046", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459860050000, - "trace.id": "00000000000000000000000000000045", - "transaction.id": "0000000000000044", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459860000, @@ -986,9 +986,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459920000000, - "trace.id": "00000000000000000000000000000049", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000048", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -999,20 +999,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000048", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000050", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459920050000, - "trace.id": "00000000000000000000000000000049", - "transaction.id": "0000000000000048", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459920000, @@ -1067,9 +1067,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609459980000000, - "trace.id": "00000000000000000000000000000053", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000052", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -1080,20 +1080,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000052", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000054", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609459980050000, - "trace.id": "00000000000000000000000000000053", - "transaction.id": "0000000000000052", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609459980000, @@ -1148,9 +1148,9 @@ Array [ "service.name": "opbeans-java", "service.node.name": "instance-1", "timestamp.us": 1609460040000000, - "trace.id": "00000000000000000000000000000057", + "trace.id": Any, "transaction.duration.us": 1000000, - "transaction.id": "0000000000000056", + "transaction.id": Any, "transaction.name": "GET /api/product/list", "transaction.sampled": true, "transaction.type": "request", @@ -1161,20 +1161,20 @@ Array [ "container.id": "instance-1", "event.outcome": "success", "host.name": "instance-1", - "parent.id": "0000000000000056", + "parent.id": Any, "processor.event": "span", "processor.name": "transaction", "service.environment": "production", "service.name": "opbeans-java", "service.node.name": "instance-1", "span.duration.us": 900000, - "span.id": "0000000000000058", + "span.id": Any, "span.name": "GET apm-*/_search", "span.subtype": "elasticsearch", "span.type": "db", "timestamp.us": 1609460040050000, - "trace.id": "00000000000000000000000000000057", - "transaction.id": "0000000000000056", + "trace.id": Any, + "transaction.id": Any, }, Object { "@timestamp": 1609460040000, diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts index e61762629a537..31030036c1ae1 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts @@ -6,7 +6,7 @@ */ import { getErrorGroupingKey } from '@kbn/apm-synthtrace-client/src/lib/apm/instance'; -import { generateLongId } from '@kbn/apm-synthtrace-client/src/lib/utils/generate_id'; +import { generateLongIdWithSeed } from '@kbn/apm-synthtrace-client/src/lib/utils/generate_id'; import url from 'url'; import { synthtrace } from '../../../synthtrace'; @@ -71,7 +71,7 @@ describe('Error details', () => { }); describe('when error has data', () => { - const errorGroupingKey = generateLongId('Error 1'); + const errorGroupingKey = generateLongIdWithSeed('Error 1'); const errorGroupingKeyShort = errorGroupingKey.slice(0, 5); const errorDetailsPageHref = url.format({ pathname: `/app/apm/services/opbeans-java/errors/${errorGroupingKey}`, diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/transaction_details/large_trace_in_waterfall/large_traces_in_waterfall.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/transaction_details/large_trace_in_waterfall/large_traces_in_waterfall.cy.ts index 5f40687274fb5..915ea4de95bc8 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/transaction_details/large_trace_in_waterfall/large_traces_in_waterfall.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/transaction_details/large_trace_in_waterfall/large_traces_in_waterfall.cy.ts @@ -42,7 +42,9 @@ describe('Large Trace in waterfall', () => { }); it('renders waterfall items', () => { - cy.getByTestSubj('waterfallItem').should('have.length.greaterThan', 200); + // it renders a virtual list, so the number of items rendered is not the same as the number of items in the trace + cy.getByTestSubj('waterfallItem').should('have.length.at.least', 39); + cy.getByTestSubj('waterfall').should('have.css', 'height').and('eq', '10011px'); }); it('shows warning about trace size', () => { @@ -70,7 +72,9 @@ describe('Large Trace in waterfall', () => { }); it('renders waterfall items', () => { - cy.getByTestSubj('waterfallItem').should('have.length.greaterThan', 400); + // it renders a virtual list, so the number of items rendered is not the same as the number of items in the trace + cy.getByTestSubj('waterfallItem').should('have.length.at.least', 39); + cy.getByTestSubj('waterfall').should('have.css', 'height').and('eq', '10011px'); }); it('does not show the warning about trace size', () => { diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx index 6505ed7697290..63a7bf42c6650 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx @@ -7,7 +7,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { omit, orderBy } from 'lodash'; -import React, { useEffect, useMemo, useRef } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import { useHistory } from 'react-router-dom'; import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context'; import { useApmParams } from '../../../hooks/use_apm_params'; @@ -20,6 +20,7 @@ import { ResettingHeightRetainer } from '../../shared/height_retainer/resetting_ import { push, replace } from '../../shared/links/url_helpers'; import { useWaterfallFetcher } from '../transaction_details/use_waterfall_fetcher'; import { WaterfallWithSummary } from '../transaction_details/waterfall_with_summary'; +import { TransactionTab } from '../transaction_details/waterfall_with_summary/transaction_tabs'; import { DependencyOperationDistributionChart } from './dependency_operation_distribution_chart'; import { DetailViewHeader } from './detail_view_header'; import { maybeRedirectToAvailableSpanSample } from './maybe_redirect_to_available_span_sample'; @@ -115,9 +116,37 @@ export function DependencyOperationDetailView() { const isWaterfallLoading = spanFetch.status === FETCH_STATUS.NOT_INITIATED || (spanFetch.status === FETCH_STATUS.LOADING && samples.length === 0) || - waterfallFetch.status === FETCH_STATUS.LOADING || - !waterfallFetch.waterfall.entryWaterfallTransaction; + (waterfallFetch.status === FETCH_STATUS.LOADING && + !waterfallFetch.waterfall.entryWaterfallTransaction); + const onSampleClick = useCallback( + (sample: any) => { + push(history, { query: { spanId: sample.spanId } }); + }, + [history] + ); + + const onTabClick = useCallback( + (nextDetailTab: TransactionTab) => { + push(history, { + query: { + detailTab: nextDetailTab, + }, + }); + }, + [history] + ); + + const onShowCriticalPathChange = useCallback( + (nextShowCriticalPath: boolean) => { + push(history, { + query: { + showCriticalPath: nextShowCriticalPath ? 'true' : 'false', + }, + }); + }, + [history] + ); return ( @@ -147,31 +176,18 @@ export function DependencyOperationDetailView() { { - push(history, { query: { spanId: sample.spanId } }); - }} - onTabClick={(tab) => { - push(history, { - query: { - detailTab: tab, - }, - }); - }} + onSampleClick={onSampleClick} + onTabClick={onTabClick} serviceName={waterfallFetch.waterfall.entryWaterfallTransaction?.doc.service.name} waterfallItemId={waterfallItemId} detailTab={detailTab} selectedSample={selectedSample || null} showCriticalPath={showCriticalPath} - onShowCriticalPathChange={(nextShowCriticalPath) => { - push(history, { - query: { - showCriticalPath: nextShowCriticalPath ? 'true' : 'false', - }, - }); - }} + onShowCriticalPathChange={onShowCriticalPathChange} /> diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/trace_explorer/trace_explorer_waterfall.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/trace_explorer/trace_explorer_waterfall.tsx index 3a65c865f574c..1bda6985e534e 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/trace_explorer/trace_explorer_waterfall.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/trace_explorer/trace_explorer_waterfall.tsx @@ -4,14 +4,17 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect } from 'react'; +import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public'; +import React, { useCallback, useEffect } from 'react'; import { useHistory } from 'react-router-dom'; import { useApmParams } from '../../../hooks/use_apm_params'; import { useTimeRange } from '../../../hooks/use_time_range'; import { useTraceExplorerSamples } from '../../../hooks/use_trace_explorer_samples'; +import { ResettingHeightRetainer } from '../../shared/height_retainer/resetting_height_container'; import { push, replace } from '../../shared/links/url_helpers'; import { useWaterfallFetcher } from '../transaction_details/use_waterfall_fetcher'; import { WaterfallWithSummary } from '../transaction_details/waterfall_with_summary'; +import { TransactionTab } from '../transaction_details/waterfall_with_summary/transaction_tabs'; export function TraceExplorerWaterfall() { const history = useHistory(); @@ -52,39 +55,61 @@ export function TraceExplorerWaterfall() { end, }); + const onSampleClick = useCallback( + (sample: any) => { + push(history, { + query: { + traceId: sample.traceId, + transactionId: sample.transactionId, + waterfallItemId: '', + }, + }); + }, + [history] + ); + + const onTabClick = useCallback( + (nextDetailTab: TransactionTab) => { + push(history, { + query: { + detailTab: nextDetailTab, + }, + }); + }, + [history] + ); + + const onShowCriticalPathChange = useCallback( + (nextShowCriticalPath: boolean) => { + push(history, { + query: { + showCriticalPath: nextShowCriticalPath ? 'true' : 'false', + }, + }); + }, + [history] + ); + + const isWaterfallLoading = + waterfallFetchResult.status === FETCH_STATUS.LOADING && + !waterfallFetchResult.waterfall.entryWaterfallTransaction; + return ( - { - push(history, { - query: { - traceId: sample.traceId, - transactionId: sample.transactionId, - waterfallItemId: '', - }, - }); - }} - onTabClick={(nextDetailTab) => { - push(history, { - query: { - detailTab: nextDetailTab, - }, - }); - }} - detailTab={detailTab} - waterfallItemId={waterfallItemId} - serviceName={waterfallFetchResult.waterfall.entryWaterfallTransaction?.doc.service.name} - showCriticalPath={showCriticalPath} - onShowCriticalPathChange={(nextShowCriticalPath) => { - push(history, { - query: { - showCriticalPath: nextShowCriticalPath ? 'true' : 'false', - }, - }); - }} - /> + + + ); } diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/distribution/index.tsx index 31c989169f26f..f7a976b3cc82d 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/distribution/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/distribution/index.tsx @@ -92,6 +92,20 @@ export function TransactionDistribution({ [history] ); + const onSampleClick = useCallback( + (sample: { transactionId: string; traceId: string }) => { + history.push({ + ...history.location, + search: fromQuery({ + ...toQuery(history.location.search), + transactionId: sample.transactionId, + traceId: sample.traceId, + }), + }); + }, + [history] + ); + return (
@@ -111,21 +125,13 @@ export function TransactionDistribution({ { - history.push({ - ...history.location, - search: fromQuery({ - ...toQuery(history.location.search), - transactionId: sample.transactionId, - traceId: sample.traceId, - }), - }); - }} + onSampleClick={onSampleClick} onTabClick={onTabClick} serviceName={serviceName} waterfallItemId={waterfallItemId} detailTab={detailTab as TransactionTab | undefined} - waterfallFetchResult={waterfallFetchResult} + waterfallFetchResult={waterfallFetchResult.waterfall} + waterfallFetchStatus={waterfallFetchResult.status} traceSamplesFetchStatus={traceSamplesFetchResult.status} traceSamples={traceSamplesFetchResult.data?.traceSamples} showCriticalPath={showCriticalPath} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx index c4008570f5c0b..4c52c2df57432 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx @@ -25,9 +25,10 @@ import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; import { WaterfallFetchResult } from '../use_waterfall_fetcher'; interface Props { - waterfallFetchResult: WaterfallFetchResult; + waterfallFetchResult: WaterfallFetchResult['waterfall']; traceSamples?: TSample[]; traceSamplesFetchStatus: FETCH_STATUS; + waterfallFetchStatus: FETCH_STATUS; environment: Environment; onSampleClick: (sample: TSample) => void; onTabClick: (tab: TransactionTab) => void; @@ -41,6 +42,7 @@ interface Props { export function WaterfallWithSummary({ waterfallFetchResult, + waterfallFetchStatus, traceSamples, traceSamplesFetchStatus, environment, @@ -58,12 +60,12 @@ export function WaterfallWithSummary({ const isControlled = selectedSample !== undefined; const isLoading = - waterfallFetchResult.status === FETCH_STATUS.LOADING || + waterfallFetchStatus === FETCH_STATUS.LOADING || traceSamplesFetchStatus === FETCH_STATUS.LOADING; // When traceId is not present, call to waterfallFetchResult will not be initiated const isSucceded = - (waterfallFetchResult.status === FETCH_STATUS.SUCCESS || - waterfallFetchResult.status === FETCH_STATUS.NOT_INITIATED) && + (waterfallFetchStatus === FETCH_STATUS.SUCCESS || + waterfallFetchStatus === FETCH_STATUS.NOT_INITIATED) && traceSamplesFetchStatus === FETCH_STATUS.SUCCESS; useEffect(() => { @@ -86,7 +88,7 @@ export function WaterfallWithSummary({ : 0 : sampleActivePage; - const { entryTransaction } = waterfallFetchResult.waterfall; + const { entryTransaction } = waterfallFetchResult; if (!entryTransaction && traceSamples?.length === 0 && isSucceded) { return ( @@ -136,7 +138,7 @@ export function WaterfallWithSummary({ @@ -153,8 +155,8 @@ export function WaterfallWithSummary({ ) : ( @@ -167,7 +169,7 @@ export function WaterfallWithSummary({ serviceName={serviceName} waterfallItemId={waterfallItemId} onTabClick={onTabClick} - waterfall={waterfallFetchResult.waterfall} + waterfall={waterfallFetchResult} isLoading={isLoading} showCriticalPath={showCriticalPath} onShowCriticalPathChange={onShowCriticalPathChange} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx index c807731057594..d0197f23d5fd5 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx @@ -15,20 +15,24 @@ import { EuiToolTip, } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { groupBy } from 'lodash'; import { transparentize } from 'polished'; -import React, { useState } from 'react'; +import React, { useEffect, useRef } from 'react'; +import { WindowScroller, AutoSizer } from 'react-virtualized'; +import { areEqual, ListChildComponentProps, VariableSizeList as List } from 'react-window'; import { asBigNumber } from '../../../../../../../common/utils/formatters'; -import { getCriticalPath } from '../../../../../../../common/critical_path/get_critical_path'; import { useTheme } from '../../../../../../hooks/use_theme'; import { Margins } from '../../../../../shared/charts/timeline'; -import { IWaterfall, IWaterfallSpanOrTransaction } from './waterfall_helpers/waterfall_helpers'; +import { + IWaterfallNodeFlatten, + IWaterfall, + IWaterfallSpanOrTransaction, +} from './waterfall_helpers/waterfall_helpers'; import { WaterfallItem } from './waterfall_item'; +import { WaterfallContextProvider } from './context/waterfall_context'; +import { useWaterfallContext } from './context/use_waterfall'; interface AccordionWaterfallProps { isOpen: boolean; - item: IWaterfallSpanOrTransaction; - level: number; duration: IWaterfall['duration']; waterfallItemId?: string; waterfall: IWaterfall; @@ -38,24 +42,27 @@ interface AccordionWaterfallProps { maxLevelOpen: number; } -const ACCORDION_HEIGHT = '48px'; +type WaterfallProps = Omit< + AccordionWaterfallProps, + 'item' | 'maxLevelOpen' | 'showCriticalPath' | 'waterfall' | 'isOpen' +>; + +interface WaterfallNodeProps extends WaterfallProps { + node: IWaterfallNodeFlatten; +} + +const ACCORDION_HEIGHT = 48; const StyledAccordion = euiStyled(EuiAccordion).withConfig({ - shouldForwardProp: (prop) => !['childrenCount', 'marginLeftLevel', 'hasError'].includes(prop), + shouldForwardProp: (prop) => !['marginLeftLevel', 'hasError'].includes(prop), })< EuiAccordionProps & { - childrenCount: number; marginLeftLevel: number; hasError: boolean; } >` - .waterfall_accordion { - border-top: 1px solid ${({ theme }) => theme.eui.euiColorLightShade}; - } - .euiAccordion__childWrapper { - transition: none; - } + border-top: 1px solid ${({ theme }) => theme.eui.euiColorLightShade}; ${(props) => { const borderLeft = props.hasError @@ -63,7 +70,7 @@ const StyledAccordion = euiStyled(EuiAccordion).withConfig({ : `1px solid ${props.theme.eui.euiColorLightShade};`; return `.button_${props.id} { width: 100%; - height: ${ACCORDION_HEIGHT}; + height: ${ACCORDION_HEIGHT}px; margin-left: ${props.marginLeftLevel}px; border-left: ${borderLeft} &:hover { @@ -78,111 +85,166 @@ const StyledAccordion = euiStyled(EuiAccordion).withConfig({ } `; -export function AccordionWaterfall(props: AccordionWaterfallProps) { - const { - item, - level, - duration, - waterfall, - waterfallItemId, - timelineMargins, - onClickWaterfallItem, - showCriticalPath, - maxLevelOpen, - } = props; - const theme = useTheme(); +export function AccordionWaterfall({ + maxLevelOpen, + showCriticalPath, + waterfall, + isOpen, + ...props +}: AccordionWaterfallProps) { + return ( + + + + ); +} - const [isOpen, setIsOpen] = useState(props.isOpen); +function Waterfall(props: WaterfallProps) { + const listRef = useRef(null); + const rowSizeMapRef = useRef(new Map()); + const { traceList } = useWaterfallContext(); - let children = waterfall.childrenByParentId[item.id] || []; + const onRowLoad = (index: number, size: number) => { + rowSizeMapRef.current.set(index, size); + }; - const criticalPath = showCriticalPath ? getCriticalPath(waterfall) : undefined; + const getRowSize = (index: number) => { + // adds 1px for the border top + return rowSizeMapRef.current.get(index) || ACCORDION_HEIGHT + 1; + }; - const criticalPathSegmentsById = groupBy(criticalPath?.segments, (segment) => segment.item.id); + const onScroll = ({ scrollTop }: { scrollTop: number }) => { + listRef.current?.scrollTo(scrollTop); + }; - let displayedColor = item.color; + return ( + + {({ registerChild }) => ( + + {({ width }) => ( +
+ + {VirtualRow} + +
+ )} +
+ )} +
+ ); +} - if (showCriticalPath) { - children = children.filter((child) => criticalPathSegmentsById[child.id]?.length); - displayedColor = transparentize(0.5, item.color); - } +const VirtualRow = React.memo( + ({ + index, + style, + data, + }: ListChildComponentProps< + Omit & { + traceList: IWaterfallNodeFlatten[]; + onLoad: (index: number, size: number) => void; + } + >) => { + const { onLoad, traceList, ...props } = data; - const errorCount = waterfall.getErrorCount(item.id); + const ref = React.useRef(null); + useEffect(() => { + onLoad(index, ref.current?.getBoundingClientRect().height ?? ACCORDION_HEIGHT); + }, [index, onLoad]); - // To indent the items creating the parent/child tree - const marginLeftLevel = 8 * level; + return ( +
+ +
+ ); + }, + areEqual +); - function toggleAccordion() { - setIsOpen((isCurrentOpen) => !isCurrentOpen); - } +const WaterfallNode = React.memo((props: WaterfallNodeProps) => { + const theme = useTheme(); + const { duration, waterfallItemId, onClickWaterfallItem, timelineMargins, node } = props; + const { criticalPathSegmentsById, getErrorCount, updateTreeNode, showCriticalPath } = + useWaterfallContext(); - const hasToggle = !!children.length; + const displayedColor = showCriticalPath ? transparentize(0.5, node.item.color) : node.item.color; + const marginLeftLevel = 8 * node.level; + const hasToggle = !!node.childrenToLoad; + const errorCount = getErrorCount(node.item.id); + + const segments = criticalPathSegmentsById[node.item.id] + ?.filter((segment) => segment.self) + .map((segment) => ({ + id: segment.item.id, + color: theme.eui.euiColorAccent, + left: (segment.offset - node.item.offset - node.item.skew) / node.item.duration, + width: segment.duration / node.item.duration, + })); + + const toggleAccordion = () => { + updateTreeNode({ ...node, expanded: !node.expanded }); + }; + + const onWaterfallItemClick = (flyoutDetailTab: string) => { + onClickWaterfallItem(node.item, flyoutDetailTab); + }; return ( + { - onClickWaterfallItem(item, flyoutDetailTab); - }} - segments={criticalPathSegmentsById[item.id] - ?.filter((segment) => segment.self) - .map((segment) => ({ - color: theme.eui.euiColorAccent, - left: (segment.offset - item.offset - item.skew) / item.duration, - width: segment.duration / item.duration, - }))} + onClick={onWaterfallItemClick} + segments={segments} /> } arrowDisplay="none" - initialIsOpen={true} - forceState={isOpen ? 'open' : 'closed'} + initialIsOpen + forceState={node.expanded ? 'open' : 'closed'} onToggle={toggleAccordion} - > - {isOpen && - children.map((child) => ( - level} - level={level + 1} - item={child} - /> - ))} - + /> ); -} +}); function ToggleAccordionButton({ show, @@ -206,7 +268,7 @@ function ToggleAccordionButton({ display: 'flex', }} > - + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
; + showCriticalPath: boolean; + traceList: IWaterfallNodeFlatten[]; + getErrorCount: (waterfallItemId: string) => number; + updateTreeNode: (newTree: IWaterfallNodeFlatten) => void; + } & Pick +>({ + criticalPathSegmentsById: {} as Dictionary, + showCriticalPath: false, + traceList: [], + getErrorCount: () => 0, + updateTreeNode: () => undefined, +}); + +export function WaterfallContextProvider({ + showCriticalPath, + waterfall, + maxLevelOpen, + children, + isOpen, +}: PropsWithChildren) { + const [tree, setTree] = useState(null); + const criticalPathSegmentsById = useMemo(() => { + if (!showCriticalPath) { + return {}; + } + + const criticalPath = getCriticalPath(waterfall); + return groupBy(criticalPath.segments, (segment) => segment.item.id); + }, [showCriticalPath, waterfall]); + + const traceList = useMemo(() => { + return convertTreeToList(tree); + }, [tree]); + + const getErrorCount = useCallback( + (waterfallItemId) => waterfall.getErrorCount(waterfallItemId), + [waterfall] + ); + + const updateTreeNode = useCallback( + (updatedNode: IWaterfallNodeFlatten) => { + if (!tree) return; + + const newTree = updateTraceTreeNode({ + root: tree, + updatedNode, + waterfall, + path: { + criticalPathSegmentsById, + showCriticalPath, + }, + }); + + if (newTree) { + setTree(newTree); + } + }, + [criticalPathSegmentsById, showCriticalPath, tree, waterfall] + ); + + useEffect(() => { + const root = buildTraceTree({ + waterfall, + maxLevelOpen, + isOpen, + path: { + criticalPathSegmentsById, + showCriticalPath, + }, + }); + + setTree(root); + }, [criticalPathSegmentsById, isOpen, maxLevelOpen, showCriticalPath, waterfall]); + + return ( + + {children} + + ); +} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/index.tsx index 54ff6f86fb734..dbdc877742e1c 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/index.tsx @@ -11,7 +11,12 @@ import { History } from 'history'; import React, { useMemo, useState } from 'react'; import { useHistory } from 'react-router-dom'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { Timeline } from '../../../../../shared/charts/timeline'; +import { css } from '@emotion/react'; +import { useTheme } from '../../../../../../hooks/use_theme'; +import { + VerticalLinesContainer, + TimelineAxisContainer, +} from '../../../../../shared/charts/timeline'; import { fromQuery, toQuery } from '../../../../../shared/links/url_helpers'; import { getAgentMarks } from '../marks/get_agent_marks'; import { getErrorMarks } from '../marks/get_error_marks'; @@ -22,7 +27,6 @@ import { IWaterfall, IWaterfallItem } from './waterfall_helpers/waterfall_helper const Container = euiStyled.div` transition: 0.1s padding ease; position: relative; - overflow: hidden; `; const toggleFlyout = ({ @@ -59,35 +63,35 @@ function getWaterfallMaxLevel(waterfall: IWaterfall) { if (!entryId) { return 0; } + let maxLevel = 1; - function countLevels(id: string, currentLevel: number) { + const visited = new Set(); + const queue: Array<{ id: string; level: number }> = [{ id: entryId, level: 1 }]; + + while (queue.length > 0) { + const { id, level } = queue.shift()!; const children = waterfall.childrenByParentId[id] || []; - if (children.length) { - children.forEach((child) => { - // Skip processing when a child node has the same ID as its parent - // to prevent infinite loop - if (child.id !== id) { - countLevels(child.id, currentLevel + 1); - } - }); - } else { - if (maxLevel < currentLevel) { - maxLevel = currentLevel; + + maxLevel = Math.max(maxLevel, level); + visited.add(id); + + children.forEach((child) => { + if (child.id !== id && !visited.has(child.id)) { + queue.push({ id: child.id, level: level + 1 }); + visited.add(child.id); } - } + }); } - countLevels(entryId, 1); return maxLevel; } -// level starts with 0 -const maxLevelOpen = 2; + +const MAX_DEPTH_OPEN_LIMIT = 2; export function Waterfall({ waterfall, waterfallItemId, showCriticalPath }: Props) { const history = useHistory(); + const theme = useTheme(); const [isAccordionOpen, setIsAccordionOpen] = useState(true); - const itemContainerHeight = 58; // TODO: This is a nasty way to calculate the height of the svg element. A better approach should be found - const waterfallHeight = itemContainerHeight * waterfall.items.length; const { duration } = waterfall; @@ -124,47 +128,59 @@ export function Waterfall({ waterfall, waterfallItemId, showCriticalPath }: Prop })} /> )} -
-
- { - setIsAccordionOpen((isOpen) => !isOpen); - }} - /> - -
- - {!waterfall.entryWaterfallTransaction ? null : ( - - toggleFlyout({ history, item, flyoutDetailTab }) - } - showCriticalPath={showCriticalPath} - maxLevelOpen={ - waterfall.traceDocsTotal > 500 ? maxLevelOpen : waterfall.traceDocsTotal - } - /> - )} - + +
+ { + setIsAccordionOpen((isOpen) => !isOpen); + }} + /> +
+ + + {!waterfall.entryWaterfallTransaction ? null : ( + + toggleFlyout({ history, item, flyoutDetailTab }) + } + showCriticalPath={showCriticalPath} + maxLevelOpen={ + waterfall.traceDocsTotal > 500 ? MAX_DEPTH_OPEN_LIMIT : waterfall.traceDocsTotal + } + /> + )} + + { - describe('getWaterfall', () => { - const hits = [ - { - processor: { event: 'transaction' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { - duration: { us: 49660 }, - name: 'GET /api', - id: 'myTransactionId1', - }, - timestamp: { us: 1549324795784006 }, - } as Transaction, - { - parent: { id: 'mySpanIdA' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId2' }, - timestamp: { us: 1549324795825633 }, - span: { - duration: { us: 481 }, - name: 'SELECT FROM products', - id: 'mySpanIdB', - }, - } as Span, - { - parent: { id: 'myTransactionId2' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId2' }, - span: { - duration: { us: 6161 }, - name: 'Api::ProductsController#index', - id: 'mySpanIdA', - }, - timestamp: { us: 1549324795824504 }, - } as Span, - { - parent: { id: 'mySpanIdA' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId2' }, - span: { - duration: { us: 532 }, - name: 'SELECT FROM product', - id: 'mySpanIdC', - }, - timestamp: { us: 1549324795827905 }, - } as Span, - { - parent: { id: 'myTransactionId1' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 47557 }, - name: 'GET opbeans-ruby:3000/api/products', - id: 'mySpanIdD', - }, - timestamp: { us: 1549324795785760 }, - } as Span, - { - parent: { id: 'mySpanIdD' }, - processor: { event: 'transaction' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { - duration: { us: 8634 }, - name: 'Api::ProductsController#index', - id: 'myTransactionId2', - marks: { - agent: { - domInteractive: 382, - domComplete: 383, - timeToFirstByte: 14, - }, - }, - }, - timestamp: { us: 1549324795823304 }, - } as unknown as Transaction, - ]; - const errorDocs = [ - { - processor: { event: 'error' }, - parent: { id: 'myTransactionId1' }, - timestamp: { us: 1549324795810000 }, - trace: { id: 'myTraceId' }, - transaction: { id: 'myTransactionId1' }, - error: { - id: 'error1', - grouping_key: 'errorGroupingKey1', - log: { - message: 'error message', + const hits = [ + { + processor: { event: 'transaction' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { + duration: { us: 49660 }, + name: 'GET /api', + id: 'myTransactionId1', + }, + timestamp: { us: 1549324795784006 }, + } as Transaction, + { + parent: { id: 'mySpanIdA' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId2' }, + timestamp: { us: 1549324795825633 }, + span: { + duration: { us: 481 }, + name: 'SELECT FROM products', + id: 'mySpanIdB', + }, + } as Span, + { + parent: { id: 'myTransactionId2' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId2' }, + span: { + duration: { us: 6161 }, + name: 'Api::ProductsController#index', + id: 'mySpanIdA', + }, + timestamp: { us: 1549324795824504 }, + } as Span, + { + parent: { id: 'mySpanIdA' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId2' }, + span: { + duration: { us: 532 }, + name: 'SELECT FROM product', + id: 'mySpanIdC', + }, + timestamp: { us: 1549324795827905 }, + } as Span, + { + parent: { id: 'myTransactionId1' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 47557 }, + name: 'GET opbeans-ruby:3000/api/products', + id: 'mySpanIdD', + }, + timestamp: { us: 1549324795785760 }, + } as Span, + { + parent: { id: 'mySpanIdD' }, + processor: { event: 'transaction' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { + duration: { us: 8634 }, + name: 'Api::ProductsController#index', + id: 'myTransactionId2', + marks: { + agent: { + domInteractive: 382, + domComplete: 383, + timeToFirstByte: 14, }, }, - service: { name: 'opbeans-ruby' }, - agent: { - name: 'ruby', - version: '2', + }, + timestamp: { us: 1549324795823304 }, + } as unknown as Transaction, + ]; + const errorDocs = [ + { + processor: { event: 'error' }, + parent: { id: 'myTransactionId1' }, + timestamp: { us: 1549324795810000 }, + trace: { id: 'myTraceId' }, + transaction: { id: 'myTransactionId1' }, + error: { + id: 'error1', + grouping_key: 'errorGroupingKey1', + log: { + message: 'error message', }, - } as unknown as APMError, - ]; + }, + service: { name: 'opbeans-ruby' }, + agent: { + name: 'ruby', + version: '2', + }, + } as unknown as APMError, + ]; + describe('getWaterfall', () => { it('should return full waterfall', () => { const apiResp = { traceItems: { @@ -750,4 +755,229 @@ describe('waterfall_helpers', () => { expect(getOrphanTraceItemsCount(traceItems)).toBe(1); }); }); + + describe('#trace tree', () => { + const waterfall = getWaterfall({ + traceItems: { + traceDocs: hits, + errorDocs, + exceedsMax: false, + spanLinksCountById: {}, + traceDocsTotal: hits.length, + maxTraceItems: 5000, + }, + entryTransaction: { + processor: { event: 'transaction' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { + duration: { us: 49660 }, + name: 'GET /api', + id: 'myTransactionId1', + }, + timestamp: { us: 1549324795784006 }, + } as Transaction, + }); + + const tree: IWaterfallNode = { + id: 'myTransactionId1', + item: { + docType: 'transaction', + doc: { + agent: { name: 'nodejs' }, + processor: { event: 'transaction' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { + duration: { us: 49660 }, + name: 'GET /api', + id: 'myTransactionId1', + type: 'request', + }, + timestamp: { us: 1549324795784006 }, + }, + id: 'myTransactionId1', + duration: 49660, + offset: 0, + skew: 0, + legendValues: { serviceName: 'opbeans-node', spanType: '' }, + color: '', + spanLinksCount: { linkedParents: 0, linkedChildren: 0 }, + }, + children: [ + { + id: '0-mySpanIdD-0', + item: { + docType: 'span', + doc: { + agent: { name: 'nodejs' }, + parent: { id: 'myTransactionId1' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 47557 }, + name: 'GET opbeans-ruby:3000/api/products', + id: 'mySpanIdD', + type: 'request', + }, + timestamp: { us: 1549324795785760 }, + }, + id: 'mySpanIdD', + parentId: 'myTransactionId1', + duration: 47557, + offset: 1754, + skew: 0, + legendValues: { serviceName: 'opbeans-node', spanType: '' }, + color: '', + spanLinksCount: { linkedParents: 0, linkedChildren: 0 }, + }, + children: [], + childrenToLoad: 1, + level: 1, + expanded: false, + hasInitializedChildren: false, + }, + ], + level: 0, + childrenToLoad: 1, + expanded: true, + hasInitializedChildren: true, + }; + + describe('buildTraceTree', () => { + it('should build the trace tree correctly', () => { + const result = buildTraceTree({ + waterfall, + path: { + criticalPathSegmentsById: {}, + showCriticalPath: false, + }, + maxLevelOpen: 1, + isOpen: true, + }); + + expect(result).toEqual( + expect.objectContaining({ + item: expect.objectContaining({ id: 'myTransactionId1' }), + level: 0, + expanded: true, + hasInitializedChildren: true, + }) + ); + + expect(result?.children[0]).toEqual( + expect.objectContaining({ + item: expect.objectContaining({ id: 'mySpanIdD' }), + level: 1, + expanded: false, + childrenToLoad: 1, + children: [], + hasInitializedChildren: false, + }) + ); + }); + }); + + describe('convertTreeToList', () => { + it('should convert the trace tree to a list correctly', () => { + const result = convertTreeToList(tree); + + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + item: expect.objectContaining({ id: 'myTransactionId1' }), + level: 0, + expanded: true, + hasInitializedChildren: true, + childrenToLoad: 1, + }), + expect.objectContaining({ + item: expect.objectContaining({ id: 'mySpanIdD' }), + level: 1, + expanded: false, + hasInitializedChildren: false, + childrenToLoad: 1, + }), + ]) + ); + }); + }); + + describe('updateTraceTreeNode', () => { + it('should update the "mySpanIdD" node setting "expanded" to true', () => { + const updatedNode: IWaterfallNodeFlatten = { + id: '0-mySpanIdD-0', + item: { + docType: 'span', + doc: { + agent: { name: 'nodejs' }, + parent: { id: 'myTransactionId1' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 47557 }, + name: 'GET opbeans-ruby:3000/api/products', + id: 'mySpanIdD', + type: 'request', + }, + timestamp: { us: 1549324795785760 }, + }, + id: 'mySpanIdD', + parentId: 'myTransactionId1', + duration: 47557, + offset: 1754, + skew: 0, + legendValues: { serviceName: 'opbeans-node', spanType: '' }, + color: '', + spanLinksCount: { linkedParents: 0, linkedChildren: 0 }, + }, + childrenToLoad: 1, + level: 1, + expanded: true, + hasInitializedChildren: false, + }; + + const result = updateTraceTreeNode({ + root: tree, + updatedNode, + waterfall, + path: { + criticalPathSegmentsById: {}, + showCriticalPath: false, + }, + }); + + expect(result).toEqual( + expect.objectContaining({ + item: expect.objectContaining({ id: 'myTransactionId1' }), + level: 0, + expanded: true, + hasInitializedChildren: true, + }) + ); + + expect(result?.children[0]).toEqual( + expect.objectContaining({ + item: expect.objectContaining({ id: 'mySpanIdD' }), + level: 1, + expanded: true, + hasInitializedChildren: true, + }) + ); + + expect(result?.children[0].children[0]).toEqual( + expect.objectContaining({ + item: expect.objectContaining({ id: 'myTransactionId2' }), + level: 2, + expanded: false, + hasInitializedChildren: false, + }) + ); + }); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts index 4d96da07e42fe..b9a8f1d8cd15c 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts @@ -6,8 +6,9 @@ */ import { euiPaletteColorBlind } from '@elastic/eui'; -import { first, flatten, groupBy, isEmpty, sortBy, uniq } from 'lodash'; +import { Dictionary, first, flatten, groupBy, isEmpty, sortBy, uniq } from 'lodash'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { CriticalPathSegment } from '../../../../../../../../common/critical_path/types'; import type { APIReturnType } from '../../../../../../../services/rest/create_call_apm_api'; import type { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { @@ -93,6 +94,23 @@ export interface IWaterfallLegend { color: string; } +export interface IWaterfallNode { + id: string; + item: IWaterfallItem; + // children that are loaded + children: IWaterfallNode[]; + // total number of children that needs to be loaded + childrenToLoad: number; + // collapsed or expanded state + expanded: boolean; + // level in the tree + level: number; + // flag to indicate if children are loaded + hasInitializedChildren: boolean; +} + +export type IWaterfallNodeFlatten = Omit; + function getLegendValues(transactionOrSpan: WaterfallTransaction | WaterfallSpan) { return { [WaterfallLegendType.ServiceName]: transactionOrSpan.service.name, @@ -462,3 +480,186 @@ export function getWaterfall(apiResponse: TraceAPIResponse): IWaterfall { orphanTraceItemsCount, }; } + +function getChildren({ + path, + waterfall, + waterfallItemId, +}: { + waterfallItemId: string; + waterfall: IWaterfall; + path: { + criticalPathSegmentsById: Dictionary; + showCriticalPath: boolean; + }; +}) { + const children = waterfall.childrenByParentId[waterfallItemId] ?? []; + return path.showCriticalPath + ? children.filter((child) => path.criticalPathSegmentsById[child.id]?.length) + : children; +} + +function buildTree({ + root, + waterfall, + maxLevelOpen, + path, +}: { + root: IWaterfallNode; + waterfall: IWaterfall; + maxLevelOpen: number; + path: { + criticalPathSegmentsById: Dictionary; + showCriticalPath: boolean; + }; +}) { + const tree = { ...root }; + const queue: IWaterfallNode[] = [tree]; + + for (let queueIndex = 0; queueIndex < queue.length; queueIndex++) { + const node = queue[queueIndex]; + + const children = getChildren({ path, waterfall, waterfallItemId: node.item.id }); + + // Set childrenToLoad for all nodes enqueued. + // this allows lazy loading of child nodes + node.childrenToLoad = children.length; + + if (maxLevelOpen > node.level) { + children.forEach((child, index) => { + const level = node.level + 1; + + const currentNode: IWaterfallNode = { + id: `${level}-${child.id}-${index}`, + item: child, + children: [], + level, + expanded: level < maxLevelOpen, + childrenToLoad: 0, + hasInitializedChildren: false, + }; + + node.children.push(currentNode); + queue.push(currentNode); + }); + + node.hasInitializedChildren = true; + } + } + + return tree; +} + +export function buildTraceTree({ + waterfall, + maxLevelOpen, + isOpen, + path, +}: { + waterfall: IWaterfall; + maxLevelOpen: number; + isOpen: boolean; + path: { + criticalPathSegmentsById: Dictionary; + showCriticalPath: boolean; + }; +}): IWaterfallNode | null { + const entry = waterfall.entryWaterfallTransaction; + if (!entry) { + return null; + } + + const root: IWaterfallNode = { + id: entry.id, + item: entry, + children: [], + level: 0, + expanded: isOpen, + childrenToLoad: 0, + hasInitializedChildren: false, + }; + + return buildTree({ root, maxLevelOpen, waterfall, path }); +} + +export const convertTreeToList = (root: IWaterfallNode | null): IWaterfallNodeFlatten[] => { + if (!root) { + return []; + } + + const result: IWaterfallNodeFlatten[] = []; + const stack: IWaterfallNode[] = [root]; + + while (stack.length > 0) { + const node = stack.pop()!; + + const { children, ...nodeWithoutChildren } = node; + result.push(nodeWithoutChildren); + + if (node.expanded) { + for (let i = node.children.length - 1; i >= 0; i--) { + stack.push(node.children[i]); + } + } + } + + return result; +}; + +export const updateTraceTreeNode = ({ + root, + updatedNode, + waterfall, + path, +}: { + root: IWaterfallNode; + updatedNode: IWaterfallNodeFlatten; + waterfall: IWaterfall; + path: { + criticalPathSegmentsById: Dictionary; + showCriticalPath: boolean; + }; +}) => { + if (!root) { + return; + } + + const tree = { ...root }; + const stack: Array<{ parent: IWaterfallNode | null; index: number; node: IWaterfallNode }> = [ + { parent: null, index: 0, node: root }, + ]; + + while (stack.length > 0) { + const { parent, index, node } = stack.pop()!; + + if (node.id === updatedNode.id) { + Object.assign(node, updatedNode); + + if (updatedNode.expanded && !updatedNode.hasInitializedChildren) { + Object.assign( + node, + buildTree({ + root: node, + waterfall, + maxLevelOpen: node.level + 1, // Only one level above the current node will be loaded + path, + }) + ); + } + + if (parent) { + parent.children[index] = node; + } else { + Object.assign(tree, node); + } + + return tree; + } + + for (let i = node.children.length - 1; i >= 0; i--) { + stack.push({ parent: node, index: i, node: node.children[i] }); + } + } + + return tree; +}; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx index 6260c37ffdc5a..11d0f9bba9298 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx @@ -7,7 +7,7 @@ import { EuiBadge, EuiIcon, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { ReactNode, useRef, useState, useEffect } from 'react'; +import React, { ReactNode, useRef, useEffect, useState } from 'react'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { useTheme } from '../../../../../../hooks/use_theme'; import { isMobileAgentName, isRumAgentName } from '../../../../../../../common/agent_name'; @@ -115,6 +115,7 @@ interface IWaterfallItemProps { errorCount: number; marginLeftLevel: number; segments?: Array<{ + id: string; left: number; width: number; color: string; @@ -267,6 +268,7 @@ export function WaterfallItem({ {segments?.map((segment) => ( +
+ + + + 0 μs + + + 200 μs + + + 400 μs + + + 600 μs + + + 800 μs + + + 1,000 μs + + + +
+ + .c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + font-size: 14px; + color: #69707d; + cursor: pointer; + opacity: 1; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.c1 { + width: 11px; + height: 11px; + margin-right: 0; + background: #98a2b3; + border-radius: 100%; +} + + +
+ +
+
+
+
+ + .c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + font-size: 14px; + color: #69707d; + cursor: pointer; + opacity: 1; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.c1 { + width: 11px; + height: 11px; + margin-right: 0; + background: #98a2b3; + border-radius: 100%; +} + + +
+ +
+
+
+
+ + .c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + font-size: 14px; + color: #69707d; + cursor: pointer; + opacity: 1; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.c1 { + width: 11px; + height: 11px; + margin-right: 0; + background: #98a2b3; + border-radius: 100%; +} + + +
+ +
+
+
+
+
+`; + +exports[`Timeline VerticalLinesContainer should render with data 1`] = `
+> + + + + + + + + + + + + + + +
`; diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/index.tsx index 8c3f4ab7104e4..8b0a966b91b44 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/index.tsx @@ -22,39 +22,59 @@ export interface Margins { left: number; } -interface TimelineProps { +export interface TimelineProps { marks?: Mark[]; xMin?: number; xMax?: number; - height: number; margins: Margins; - width?: number; } -function TimeLineContainer({ width, xMin, xMax, height, marks, margins }: TimelineProps) { - if (xMax == null || !width) { +export function TimelineAxisContainer({ xMax, xMin, margins, marks }: TimelineProps) { + const [width, setWidth] = useState(0); + if (xMax === undefined) { return null; } - const plotValues = getPlotValues({ width, xMin, xMax, height, margins }); - const topTraceDuration = xMax - (xMin ?? 0); return ( - <> - - - + setWidth(size.width)}> + {(resizeRef) => { + const plotValues = getPlotValues({ width, xMin, xMax, margins }); + const topTraceDuration = xMax - (xMin ?? 0); + return ( +
+ +
+ ); + }} +
); } -export function Timeline(props: TimelineProps) { +export function VerticalLinesContainer({ xMax, xMin, margins, marks }: TimelineProps) { const [width, setWidth] = useState(0); + if (xMax == null) { + return null; + } + return ( setWidth(size.width)}> - {(resizeRef) => ( -
- -
- )} + {(resizeRef) => { + const plotValues = getPlotValues({ width, xMin, xMax, margins }); + const topTraceDuration = xMax - (xMin ?? 0); + return ( +
+ +
+ ); + }}
); } diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/plot_utils.ts b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/plot_utils.ts index 67fdc04d6529c..a099c2c39313a 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/plot_utils.ts +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/plot_utils.ts @@ -14,13 +14,11 @@ export function getPlotValues({ width, xMin = 0, xMax, - height, margins, }: { width: number; xMin?: number; xMax: number; - height: number; margins: Margins; }) { const xScale = scaleLinear() @@ -28,7 +26,6 @@ export function getPlotValues({ .range([margins.left, width - margins.right]); return { - height, margins, tickValues: xScale.ticks(7), width, diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/timeline.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/timeline.test.tsx index 82483f609a469..e6b9d30000229 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/timeline.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/timeline.test.tsx @@ -12,10 +12,10 @@ import { mockMoment, toJson, } from '../../../../utils/test_helpers'; -import { Timeline } from '.'; +import { TimelineAxisContainer, TimelineProps, VerticalLinesContainer } from '.'; import { AgentMark } from '../../../app/transaction_details/waterfall_with_summary/waterfall_container/marks/get_agent_marks'; -describe('Timeline', () => { +describe.each([[TimelineAxisContainer], [VerticalLinesContainer]])(`Timeline`, (Component) => { let consoleMock: jest.SpyInstance; beforeAll(() => { @@ -27,19 +27,15 @@ describe('Timeline', () => { consoleMock.mockRestore(); }); - it('should render with data', () => { - const props = { - traceRootDuration: 200000, - width: 1000, - duration: 200000, - height: 116, + it(`${Component.name} should render with data`, () => { + const props: TimelineProps = { + xMax: 1000, margins: { top: 100, left: 50, right: 50, bottom: 0, }, - animation: null, marks: [ { id: 'timeToFirstByte', @@ -62,17 +58,14 @@ describe('Timeline', () => { ] as AgentMark[], }; - const wrapper = mountWithTheme(); + const wrapper = mountWithTheme(); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('should not crash if traceRootDuration is 0', () => { - const props = { - traceRootDuration: 0, - width: 1000, + it(`${Component.name} should not crash if traceRootDuration is 0`, () => { + const props: TimelineProps = { xMax: 0, - height: 116, margins: { top: 100, left: 50, @@ -81,7 +74,7 @@ describe('Timeline', () => { }, }; - const mountTimeline = () => mountWithTheme(); + const mountTimeline = () => mountWithTheme(); expect(mountTimeline).not.toThrow(); }); diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/timeline_axis.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/timeline_axis.tsx index 766008d0c623f..96bc7da552f90 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/timeline_axis.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/timeline_axis.tsx @@ -6,7 +6,7 @@ */ import { inRange } from 'lodash'; -import React, { ReactNode } from 'react'; +import React from 'react'; import { getDurationFormatter } from '../../../../../common/utils/formatters'; import { useTheme } from '../../../../hooks/use_theme'; import { Mark } from '.'; @@ -30,7 +30,6 @@ const getXAxisTickValues = (tickValues: number[], topTraceDuration?: number) => }; interface TimelineAxisProps { - header?: ReactNode; plotValues: PlotValues; marks?: Mark[]; topTraceDuration: number; @@ -54,11 +53,7 @@ export function TimelineAxis({ plotValues, marks = [], topTraceDuration }: Timel return (
diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/vertical_lines.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/vertical_lines.tsx index 60e89e6b0075f..96ab6a51e49f3 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/vertical_lines.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/vertical_lines.tsx @@ -17,7 +17,7 @@ interface VerticalLinesProps { } export function VerticalLines({ topTraceDuration, plotValues, marks = [] }: VerticalLinesProps) { - const { width, height, margins, tickValues, xScale } = plotValues; + const { width, margins, tickValues, xScale } = plotValues; const markTimes = marks.filter((mark) => mark.verticalLine).map(({ offset }) => offset); @@ -38,7 +38,7 @@ export function VerticalLines({ topTraceDuration, plotValues, marks = [] }: Vert return ( ))} @@ -62,7 +62,7 @@ export function VerticalLines({ topTraceDuration, plotValues, marks = [] }: Vert x1={position} x2={position} y1={0} - y2={height} + y2="100%" stroke={theme.eui.euiColorMediumShade} /> ))} @@ -72,7 +72,7 @@ export function VerticalLines({ topTraceDuration, plotValues, marks = [] }: Vert x1={topTraceDurationPosition} x2={topTraceDurationPosition} y1={0} - y2={height} + y2="100%" stroke={theme.eui.euiColorMediumShade} /> )} From 7897e42016806a7f445fdfdae4a3b2ff84b08829 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 6 Jun 2024 10:46:14 -0400 Subject: [PATCH 20/87] [Observability Onboarding] Update copy to be stateful/serverless agnostic (#184867) ## Summary Resolves #183469. Simple change to update the copy so it will work for both Stateful and Serverless versions of Kibana. --- .../public/application/header/header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/header/header.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/header/header.tsx index e05c8cfdd0be2..79789525c8318 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/header/header.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/header/header.tsx @@ -27,7 +27,7 @@ export const Header = () => { 'xpack.observability_onboarding.experimentalOnboardingFlow.startIngestingDataIntoTextLabel', { defaultMessage: - 'Start ingesting data into your Observability project. Return to this page at any time by clicking Add data.', + 'Start ingesting Observability data into Elastic. Return to this page at any time by clicking Add data.', } )} From 202b9eea377a9417f25db0b19ede952dd9b561a8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 08:08:40 -0700 Subject: [PATCH 21/87] Update dependency @elastic/elasticsearch to ^8.13.1 (main) (#184863) --- package.json | 2 +- .../server/service/knowledge_base_service/index.ts | 1 - x-pack/plugins/security/common/model/api_key.ts | 2 +- yarn.lock | 12 ++++++------ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index ed541c789626d..f8b779401c0b0 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "@elastic/charts": "65.2.0", "@elastic/datemath": "5.0.3", "@elastic/ecs": "^8.11.1", - "@elastic/elasticsearch": "^8.13.0", + "@elastic/elasticsearch": "^8.13.1", "@elastic/ems-client": "8.5.1", "@elastic/eui": "94.6.0", "@elastic/filesaver": "1.1.2", diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts index 8281c9b5fba07..1f9ad5bc936f8 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts @@ -91,7 +91,6 @@ export class KnowledgeBaseService { input: { field_names: ['text_field'], }, - // @ts-expect-error wait_for_completion: true, }, { requestTimeout: '20m' } diff --git a/x-pack/plugins/security/common/model/api_key.ts b/x-pack/plugins/security/common/model/api_key.ts index 91b144cdc4326..639cf6568c709 100644 --- a/x-pack/plugins/security/common/model/api_key.ts +++ b/x-pack/plugins/security/common/model/api_key.ts @@ -113,5 +113,5 @@ interface BaseQueryApiKeyResult { canManageApiKeys: boolean; canManageOwnApiKeys: boolean; aggregationTotal: number; - aggregations: Record | undefined; + aggregations: Record | undefined; } diff --git a/yarn.lock b/yarn.lock index 4f691866a05af..181a7fe9a4c6c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1707,12 +1707,12 @@ "@elastic/transport" "^8.3.1" tslib "^2.4.0" -"@elastic/elasticsearch@^8.13.0": - version "8.13.0" - resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-8.13.0.tgz#625c6fba3caf944370c6859482fbd5cf3543aea8" - integrity sha512-OAYgzqArPqgDaIJ1yT0RX31YCgr1lleo53zL+36i23PFjHu08CA6Uq+BmBzEV05yEidl+ILPdeSfF3G8hPG/JQ== +"@elastic/elasticsearch@^8.13.1": + version "8.13.1" + resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-8.13.1.tgz#0fbe8318cf7f21c599165bb901277428639d57ec" + integrity sha512-2G4Vu6OHw4+XTrp7AGIcOEezpPEoVrWg2JTK1v/exEKSLYquZkUdd+m4yOL3/UZ6bTj7hmXwrmYzW76BnLCkJQ== dependencies: - "@elastic/transport" "^8.4.0" + "@elastic/transport" "~8.4.1" tslib "^2.4.0" "@elastic/ems-client@8.5.1": @@ -1887,7 +1887,7 @@ undici "^5.21.2" yaml "^2.2.2" -"@elastic/transport@^8.3.1", "@elastic/transport@^8.4.0": +"@elastic/transport@^8.3.1", "@elastic/transport@~8.4.1": version "8.4.1" resolved "https://registry.yarnpkg.com/@elastic/transport/-/transport-8.4.1.tgz#f98c5a5e2156bcb3f01170b4aca7e7de4d8b61b8" integrity sha512-/SXVuVnuU5b4dq8OFY4izG+dmGla185PcoqgK6+AJMpmOeY1QYVNbWtCwvSvoAANN5D/wV+EBU8+x7Vf9EphbA== From c3c5744f3d57d9a290d9746926971a9a7f618d4e Mon Sep 17 00:00:00 2001 From: Rodney Norris Date: Thu, 6 Jun 2024 10:10:55 -0500 Subject: [PATCH 22/87] [EntSearch] standardize side nav header to search for all apps (#184773) ## Summary Fix to ensure the solution nav name is consistent for all Search pages. --- .../ai_search/components/layout/page_template.test.tsx | 2 +- .../ai_search/components/layout/page_template.tsx | 4 ++-- .../analytics/components/layout/page_template.tsx | 4 ++-- .../applications/components/layout/page_template.tsx | 4 ++-- .../elasticsearch/components/layout/page_template.test.tsx | 2 +- .../elasticsearch/components/layout/page_template.tsx | 4 ++-- .../components/layout/page_template.tsx | 4 ++-- .../components/layout/page_template.tsx | 4 ++-- .../search_experiences/components/layout/page_template.tsx | 4 ++-- .../vector_search/components/layout/page_template.test.tsx | 2 +- .../vector_search/components/layout/page_template.tsx | 4 ++-- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/ai_search/components/layout/page_template.test.tsx b/x-pack/plugins/enterprise_search/public/applications/ai_search/components/layout/page_template.test.tsx index e5cee004d6782..42a84efd0ccc4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/ai_search/components/layout/page_template.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/ai_search/components/layout/page_template.test.tsx @@ -28,7 +28,7 @@ describe('EnterpriseSearchAISearchPageTemplate', () => { ); expect(wrapper.type()).toEqual(EnterpriseSearchPageTemplateWrapper); - expect(wrapper.prop('solutionNav')).toEqual({ name: 'AI Search', items: [] }); + expect(wrapper.prop('solutionNav')).toEqual({ name: 'Search', items: [] }); expect(wrapper.find('.hello').text()).toEqual('world'); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/ai_search/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/ai_search/components/layout/page_template.tsx index ec0c94b57455d..ea18568c29189 100644 --- a/x-pack/plugins/enterprise_search/public/applications/ai_search/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/ai_search/components/layout/page_template.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { AI_SEARCH_PLUGIN } from '../../../../../common/constants'; +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; import { SetAiSearchChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; import { useEnterpriseSearchNav } from '../../../shared/layout'; @@ -23,7 +23,7 @@ export const EnterpriseSearchAISearchPageTemplate: React.FC = } diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.tsx index 67180252e45d7..cf46363c23600 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.tsx @@ -13,7 +13,7 @@ import useObservable from 'react-use/lib/useObservable'; import type { EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; -import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; import { generateEncodedPath } from '../../../shared/encode_path_params'; import { KibanaLogic } from '../../../shared/kibana'; import { SetAnalyticsChrome } from '../../../shared/kibana_chrome'; @@ -87,7 +87,7 @@ export const EnterpriseSearchAnalyticsPageTemplate: React.FC< {...pageTemplateProps} solutionNav={{ items: chromeStyle === 'classic' ? navItems : undefined, - name: ENTERPRISE_SEARCH_CONTENT_PLUGIN.NAME, + name: SEARCH_PRODUCT_NAME, }} setPageChrome={pageChrome && } > diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.tsx index f8f390b1785b8..ec745ce77be2f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.tsx @@ -13,7 +13,7 @@ import useObservable from 'react-use/lib/useObservable'; import type { EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; -import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; import { KibanaLogic } from '../../../shared/kibana'; import { SetEnterpriseSearchApplicationsChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; @@ -99,7 +99,7 @@ export const EnterpriseSearchApplicationsPageTemplate: React.FC< {...pageTemplateProps} solutionNav={{ items: chromeStyle === 'classic' ? navItems : undefined, - name: ENTERPRISE_SEARCH_CONTENT_PLUGIN.NAME, + name: SEARCH_PRODUCT_NAME, }} restrictWidth={restrictWidth} setPageChrome={pageChrome && } diff --git a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.test.tsx b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.test.tsx index a6885bb8adc9c..99eba7d57b108 100644 --- a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.test.tsx @@ -28,7 +28,7 @@ describe('EnterpriseSearchElasticsearchPageTemplate', () => { ); expect(wrapper.type()).toEqual(EnterpriseSearchPageTemplateWrapper); - expect(wrapper.prop('solutionNav')).toEqual({ name: 'Elasticsearch', items: [] }); + expect(wrapper.prop('solutionNav')).toEqual({ name: 'Search', items: [] }); expect(wrapper.find('.hello').text()).toEqual('world'); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.tsx index 81ba64913879e..7f2eded8a6565 100644 --- a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/components/layout/page_template.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { ELASTICSEARCH_PLUGIN } from '../../../../../common/constants'; +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; import { SetElasticsearchChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; import { useEnterpriseSearchNav } from '../../../shared/layout'; @@ -24,7 +24,7 @@ export const EnterpriseSearchElasticsearchPageTemplate: React.FC} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/layout/page_template.tsx index 0ff30a31ebd34..f1f271a5e0cf2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/layout/page_template.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; import { SetEnterpriseSearchContentChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; import { useEnterpriseSearchNav } from '../../../shared/layout'; @@ -24,7 +24,7 @@ export const EnterpriseSearchContentPageTemplate: React.FC = {...pageTemplateProps} solutionNav={{ items: useEnterpriseSearchNav(), - name: ENTERPRISE_SEARCH_CONTENT_PLUGIN.NAME, + name: SEARCH_PRODUCT_NAME, }} setPageChrome={pageChrome && } > diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/layout/page_template.tsx index 0929e81d02cbe..b3589189b9a55 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/layout/page_template.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; import { SetSearchChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; import { useEnterpriseSearchNav } from '../../../shared/layout'; @@ -23,7 +23,7 @@ export const EnterpriseSearchOverviewPageTemplate: React.FC = } diff --git a/x-pack/plugins/enterprise_search/public/applications/search_experiences/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/search_experiences/components/layout/page_template.tsx index 704f9d06f3e19..11044fa04b956 100644 --- a/x-pack/plugins/enterprise_search/public/applications/search_experiences/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/search_experiences/components/layout/page_template.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; import { SetSearchExperiencesChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; import { useEnterpriseSearchNav } from '../../../shared/layout'; @@ -23,7 +23,7 @@ export const EnterpriseSearchSearchExperiencesPageTemplate: React.FC} diff --git a/x-pack/plugins/enterprise_search/public/applications/vector_search/components/layout/page_template.test.tsx b/x-pack/plugins/enterprise_search/public/applications/vector_search/components/layout/page_template.test.tsx index ab6585f5e6961..5f6fe605858bf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/vector_search/components/layout/page_template.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/vector_search/components/layout/page_template.test.tsx @@ -28,7 +28,7 @@ describe('EnterpriseSearchVectorSearchPageTemplate', () => { ); expect(wrapper.type()).toEqual(EnterpriseSearchPageTemplateWrapper); - expect(wrapper.prop('solutionNav')).toEqual({ items: [], name: 'Vector Search' }); + expect(wrapper.prop('solutionNav')).toEqual({ items: [], name: 'Search' }); expect(wrapper.find('.hello').text()).toEqual('world'); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/vector_search/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/vector_search/components/layout/page_template.tsx index 44db21bb070d9..60b998958b6b2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/vector_search/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/vector_search/components/layout/page_template.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { VECTOR_SEARCH_PLUGIN } from '../../../../../common/constants'; +import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; import { SetVectorSearchChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper, @@ -26,7 +26,7 @@ export const EnterpriseSearchVectorSearchPageTemplate: React.FC} > From 966736e4b4d9db6caa9dd870e0bc5f9a8d7e3bef Mon Sep 17 00:00:00 2001 From: Cristina Amico Date: Thu, 6 Jun 2024 17:13:52 +0200 Subject: [PATCH 23/87] [Fleet] Add rate limiting to install by upload endpoint (#184036) Fixes https://github.com/elastic/ingest-dev/issues/3217 ## Summary Add rate limiting to "install by upload" endpoint. Implemented with a cache that is set with the timestamp of each install by upload, independently from the package name/version. If the time elapsed since the last timestamp it's less than retry time (10s), the endpoint will return `429 Too many requests`. ### Testing - Upload a package with ``` curl -XPOST -H 'content-type: application/zip' -H 'kbn-xsrf: true' http://localhost:5601/YOUR_PATH/api/fleet/epm/packages -u elastic:changeme --data-binary @PACKAGE_NAME.zip ``` - Upload another package shortly after. It can be the same one or another one, as the rate limiting is applied across all uploads, no matter the package name. - If the second upload happens <10s after the first one, should return error `429 Too Many Requests. Please wait 10s before uploading again.` ### Checklist - [ ] [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 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../plugins/fleet/common/openapi/bundled.json | 3 ++ .../plugins/fleet/common/openapi/bundled.yaml | 2 + .../openapi/components/responses/error.yaml | 2 +- .../common/openapi/paths/epm@packages.yaml | 2 + .../plugins/fleet/server/errors/handlers.ts | 5 +++ x-pack/plugins/fleet/server/errors/index.ts | 2 +- .../fleet/server/routes/epm/handlers.ts | 21 +++++++++- .../services/epm/packages/install.test.ts | 16 ++++---- .../server/services/epm/packages/install.ts | 30 ++++++++++++++ .../server/services/epm/packages/utils.ts | 16 ++++++++ .../fleet_api_integration/apis/epm/file.ts | 2 + .../fleet_api_integration/apis/epm/get.ts | 39 +++++++++---------- .../apis/epm/install_bundled.ts | 6 +-- .../apis/epm/install_by_upload.ts | 35 ++++++++++++++++- .../apis/epm/remove_legacy_templates.ts | 4 +- .../apis/kibana/index.ts | 2 +- .../monitoring_api_integration/packages.ts | 4 +- 17 files changed, 148 insertions(+), 43 deletions(-) diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index 35ef539cfe299..62de596088edb 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -606,6 +606,9 @@ }, "400": { "$ref": "#/components/responses/error" + }, + "429": { + "$ref": "#/components/responses/error" } }, "operationId": "install-package-by-upload", diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index 3f2745267a5d0..ac1d7b76979ff 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -392,6 +392,8 @@ paths: - items '400': $ref: '#/components/responses/error' + '429': + $ref: '#/components/responses/error' operationId: install-package-by-upload description: '' parameters: diff --git a/x-pack/plugins/fleet/common/openapi/components/responses/error.yaml b/x-pack/plugins/fleet/common/openapi/components/responses/error.yaml index 8199a81cb6b5a..0f0c54f1c3d38 100644 --- a/x-pack/plugins/fleet/common/openapi/components/responses/error.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/responses/error.yaml @@ -9,4 +9,4 @@ content: error: type: string message: - type: string \ No newline at end of file + type: string diff --git a/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml b/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml index f8b1ccaf46fe1..7eaf0b6584915 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml @@ -79,6 +79,8 @@ post: - items '400': $ref: ../components/responses/error.yaml + '429': + $ref: ../components/responses/error.yaml operationId: install-package-by-upload description: '' parameters: diff --git a/x-pack/plugins/fleet/server/errors/handlers.ts b/x-pack/plugins/fleet/server/errors/handlers.ts index fef8cd1872413..dfd92951c8919 100644 --- a/x-pack/plugins/fleet/server/errors/handlers.ts +++ b/x-pack/plugins/fleet/server/errors/handlers.ts @@ -43,6 +43,7 @@ import { PackagePolicyRequestError, FleetNotFoundError, PackageSavedObjectConflictError, + FleetTooManyRequestsError, } from '.'; type IngestErrorHandler = ( @@ -114,6 +115,10 @@ const getHTTPResponseCode = (error: FleetError): number => { if (error instanceof PackageUnsupportedMediaTypeError) { return 415; } + // Too many requests + if (error instanceof FleetTooManyRequestsError) { + return 429; + } // Internal Server Error if (error instanceof UninstallTokenError) { return 500; diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index 6a69581c11965..02c72a5d8a25e 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -44,7 +44,6 @@ export class PackageRemovalError extends FleetError {} export class PackageESError extends FleetError {} export class ConcurrentInstallOperationError extends FleetError {} export class PackageSavedObjectConflictError extends FleetError {} - export class KibanaSOReferenceError extends FleetError {} export class PackageAlreadyInstalledError extends FleetError {} @@ -81,6 +80,7 @@ export class FleetSetupError extends FleetError {} export class GenerateServiceTokenError extends FleetError {} export class FleetUnauthorizedError extends FleetError {} export class FleetNotFoundError extends FleetError {} +export class FleetTooManyRequestsError extends FleetError {} export class OutputUnauthorizedError extends FleetError {} export class OutputInvalidError extends FleetError {} diff --git a/x-pack/plugins/fleet/server/routes/epm/handlers.ts b/x-pack/plugins/fleet/server/routes/epm/handlers.ts index e46b9d5b3445a..709bd7b362a9f 100644 --- a/x-pack/plugins/fleet/server/routes/epm/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/epm/handlers.ts @@ -65,7 +65,12 @@ import { getTemplateInputs, } from '../../services/epm/packages'; import type { BulkInstallResponse } from '../../services/epm/packages'; -import { defaultFleetErrorHandler, fleetErrorToResponseOptions, FleetError } from '../../errors'; +import { + defaultFleetErrorHandler, + fleetErrorToResponseOptions, + FleetError, + FleetTooManyRequestsError, +} from '../../errors'; import { appContextService, checkAllowedPackages } from '../../services'; import { getPackageUsageStats } from '../../services/epm/packages/get'; import { updatePackage } from '../../services/epm/packages/update'; @@ -80,6 +85,7 @@ import type { import { getDataStreams } from '../../services/epm/data_streams'; import { NamingCollisionError } from '../../services/epm/packages/custom_integrations/validation/check_naming_collision'; import { DatasetNamePrefixError } from '../../services/epm/packages/custom_integrations/validation/check_dataset_name_format'; +import { UPLOAD_RETRY_AFTER_MS } from '../../services/epm/packages/install'; const CACHE_CONTROL_10_MINUTES_HEADER: HttpResponseOptions['headers'] = { 'cache-control': 'max-age=600', @@ -451,7 +457,6 @@ export const installPackageByUploadHandler: FleetRequestHandler< const archiveBuffer = Buffer.from(request.body); const spaceId = fleetContext.spaceId; const user = (await appContextService.getSecurity()?.authc.getCurrentUser(request)) || undefined; - const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request, user?.username); const res = await installPackage({ @@ -475,6 +480,18 @@ export const installPackageByUploadHandler: FleetRequestHandler< }; return response.ok({ body }); } else { + if (res.error instanceof FleetTooManyRequestsError) { + return response.customError({ + statusCode: 429, + body: { + message: res.error.message, + }, + headers: { + // retry-after expects seconds + 'retry-after': Math.ceil(UPLOAD_RETRY_AFTER_MS / 1000).toString(), + }, + }); + } return defaultFleetErrorHandler({ error: res.error, response }); } }; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts index bbaa10728754b..14f3068795120 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts @@ -426,7 +426,6 @@ describe('install', () => { }); afterEach(() => { (install._installPackage as jest.Mock).mockClear(); - // jest.resetAllMocks(); }); afterAll(() => { jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ @@ -834,10 +833,14 @@ describe('installAssetsForInputPackagePolicy', () => { describe('handleInstallPackageFailure', () => { const mockedLogger = jest.mocked(appContextService.getLogger()); + const savedObjectsClient = savedObjectsClientMock.create(); + beforeEach(() => { + mockedLogger.error.mockClear(); jest.mocked(install._installPackage).mockClear(); + mockGetBundledPackageByPkgKey.mockReset(); + jest.mocked(install._installPackage).mockResolvedValue({} as any); - mockedLogger.error.mockClear(); mockGetBundledPackageByPkgKey.mockResolvedValue(undefined); jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); jest.spyOn(Registry, 'splitPkgKey').mockImplementation((pkgKey: string) => { @@ -860,9 +863,7 @@ describe('handleInstallPackageFailure', () => { }); const pkgName = 'test_package'; - it('should do nothing if error is ', async () => { - const savedObjectsClient = savedObjectsClientMock.create(); - + it('should do nothing if error is ConcurrentInstallOperationError', async () => { const installedPkg: SavedObject = { id: 'test-package', references: [], @@ -893,8 +894,6 @@ describe('handleInstallPackageFailure', () => { }); it('Should rollback on upgrade on FleetError', async () => { - const savedObjectsClient = savedObjectsClientMock.create(); - const installedPkg: SavedObject = { id: 'test-package', references: [], @@ -933,11 +932,10 @@ describe('handleInstallPackageFailure', () => { }), }) ); + jest.mocked(getInstallationObject).mockReset(); }); it('Should update the installation status to: install_failed on rollback error', async () => { - const savedObjectsClient = savedObjectsClientMock.create(); - jest.mocked(install._installPackage).mockRejectedValue(new Error('test error')); const installedPkg: SavedObject = { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index c5ce7e5f0eca8..9f200e97c3cfd 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -9,6 +9,7 @@ import apm from 'elastic-apm-node'; import { i18n } from '@kbn/i18n'; import semverLt from 'semver/functions/lt'; import type Boom from '@hapi/boom'; +import moment from 'moment'; import type { ElasticsearchClient, SavedObject, @@ -53,6 +54,7 @@ import { ConcurrentInstallOperationError, FleetUnauthorizedError, PackageNotFoundError, + FleetTooManyRequestsError, } from '../../../errors'; import { PACKAGES_SAVED_OBJECT_TYPE, MAX_TIME_COMPLETE_INSTALL } from '../../../constants'; import { dataStreamService, licenseService } from '../..'; @@ -89,7 +91,9 @@ import { checkDatasetsNameFormat } from './custom_integrations/validation/check_ import { addErrorToLatestFailedAttempts } from './install_errors_helpers'; import { installIndexTemplatesAndPipelines } from './install_index_template_pipeline'; import { optimisticallyAddEsAssetReferences } from './es_assets_reference'; +import { setLastUploadInstallCache, getLastUploadInstallCache } from './utils'; +export const UPLOAD_RETRY_AFTER_MS = 10000; // 10s const MAX_ENSURE_INSTALL_TIME = 60 * 1000; export async function isPackageInstalled(options: { @@ -361,6 +365,7 @@ interface InstallUploadedArchiveParams { ignoreMappingUpdateErrors?: boolean; skipDataStreamRollover?: boolean; isBundledPackage?: boolean; + skipRateLimitCheck?: boolean; } function getTelemetryEvent(pkgName: string, pkgVersion: string): PackageUpdateEvent { @@ -887,11 +892,33 @@ async function installPackageByUpload({ ignoreMappingUpdateErrors, skipDataStreamRollover, isBundledPackage, + skipRateLimitCheck, }: InstallUploadedArchiveParams): Promise { + const logger = appContextService.getLogger(); + // if an error happens during getInstallType, report that we don't know let installType: InstallType = 'unknown'; const installSource = isBundledPackage ? 'bundled' : 'upload'; + + const timeToWaitString = moment + .utc(moment.duration(UPLOAD_RETRY_AFTER_MS).asMilliseconds()) + .format('s[s]'); + try { + // Check cached timestamp for rate limiting + const lastInstalledBy = getLastUploadInstallCache(); + + if (lastInstalledBy && !skipRateLimitCheck) { + const msSinceLastFetched = Date.now() - (lastInstalledBy || 0); + if (msSinceLastFetched < UPLOAD_RETRY_AFTER_MS) { + logger.error( + `Install by Upload - Too many requests. Wait ${timeToWaitString} before uploading again.` + ); + throw new FleetTooManyRequestsError( + `Too many requests. Please wait ${timeToWaitString} before uploading again.` + ); + } + } const { packageInfo } = await generatePackageInfoFromArchiveBuffer(archiveBuffer, contentType); const pkgName = packageInfo.name; @@ -928,6 +955,8 @@ async function installPackageByUpload({ assetsMap, paths, }; + // update the timestamp of latest installation + setLastUploadInstallCache(); return await installPackageCommon({ packageInstallContext, @@ -1006,6 +1035,7 @@ export async function installPackage(args: InstallPackageParams): Promise = new Map(); + +export const setLastUploadInstallCache = () => { + const logger = appContextService.getLogger(); + const key = 'upload'; + const time = Date.now(); + logger.debug(`Setting timestamp ${time} to cache for install by ${key}`); + return lastInstalledByUpload.set(key, time); +}; + +export const getLastUploadInstallCache = () => { + return lastInstalledByUpload.get('upload'); +}; diff --git a/x-pack/test/fleet_api_integration/apis/epm/file.ts b/x-pack/test/fleet_api_integration/apis/epm/file.ts index db4c463acb96e..e44aa2f4e2634 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/file.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/file.ts @@ -21,6 +21,8 @@ export default function (providerContext: FtrProviderContext) { skipIfNoDockerRegistry(providerContext); describe('it gets files from registry', () => { it('fetches a .png screenshot image', async function () { + // wait 10s before uploading again to avoid getting 429 just in case a previous test was hitting the same endpoint + await new Promise((resolve) => setTimeout(resolve, 10000)); const res = await supertest .get('/api/fleet/epm/packages/filetest/0.1.0/img/screenshots/metricbeat_dashboard.png') .set('kbn-xsrf', 'xxx') diff --git a/x-pack/test/fleet_api_integration/apis/epm/get.ts b/x-pack/test/fleet_api_integration/apis/epm/get.ts index 7b79272bbef0b..c98bb318bdf41 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/get.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/get.ts @@ -40,6 +40,18 @@ export default function (providerContext: FtrProviderContext) { '../fixtures/direct_upload_packages/apache_0.1.4.zip' ); + async function uploadPackage(zipPackage: string) { + // wait 10s before uploading again to avoid getting 429 + await new Promise((resolve) => setTimeout(resolve, 10000)); + const buf = fs.readFileSync(zipPackage); + return await supertest + .post(`/api/fleet/epm/packages`) + .set('kbn-xsrf', 'xxxx') + .type('application/zip') + .send(buf) + .expect(200); + } + describe('EPM - get', () => { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); @@ -57,14 +69,9 @@ export default function (providerContext: FtrProviderContext) { expect(packageInfo.download).to.not.equal(undefined); await uninstallPackage(testPkgName, testPkgVersion); }); + it('returns correct package info if it was installed by upload', async function () { - const buf = fs.readFileSync(testPkgArchiveZip); - await supertest - .post(`/api/fleet/epm/packages`) - .set('kbn-xsrf', 'xxxx') - .type('application/zip') - .send(buf) - .expect(200); + await uploadPackage(testPkgArchiveZip); const res = await supertest .get(`/api/fleet/epm/packages/${testPkgName}/${testPkgVersion}`) @@ -76,14 +83,9 @@ export default function (providerContext: FtrProviderContext) { expect(packageInfo.download).to.not.equal(undefined); await uninstallPackage(testPkgName, testPkgVersion); }); + it('returns correct package info from registry if a different version is installed by upload', async function () { - const buf = fs.readFileSync(testPkgArchiveZip); - await supertest - .post(`/api/fleet/epm/packages`) - .set('kbn-xsrf', 'xxxx') - .type('application/zip') - .send(buf) - .expect(200); + await uploadPackage(testPkgArchiveZip); const res = await supertest.get(`/api/fleet/epm/packages/apache/0.1.3`).expect(200); const packageInfo = res.body.item; @@ -97,13 +99,7 @@ export default function (providerContext: FtrProviderContext) { path.dirname(__filename), '../fixtures/direct_upload_packages/apache_9999.0.0.zip' ); - const buf = fs.readFileSync(testPkgArchiveZipV9999); - await supertest - .post(`/api/fleet/epm/packages`) - .set('kbn-xsrf', 'xxxx') - .type('application/zip') - .send(buf) - .expect(200); + await uploadPackage(testPkgArchiveZipV9999); const res = await supertest.get(`/api/fleet/epm/packages/apache/9999.0.0`).expect(200); const packageInfo = res.body.item; @@ -111,6 +107,7 @@ export default function (providerContext: FtrProviderContext) { expect(packageInfo.download).to.equal(undefined); await uninstallPackage(testPkgName, '9999.0.0'); }); + describe('Installed Packages', () => { before(async () => { await installPackage(testPkgName, testPkgVersion); diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_bundled.ts b/x-pack/test/fleet_api_integration/apis/epm/install_bundled.ts index 4b91e8ac88e54..ffef558628804 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_bundled.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_bundled.ts @@ -56,7 +56,7 @@ export default function (providerContext: FtrProviderContext) { const supertest = getService('supertest'); const log = getService('log'); - describe('installing bundled packages', async () => { + describe('Installing bundled packages', async () => { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); @@ -89,7 +89,6 @@ export default function (providerContext: FtrProviderContext) { .type('application/json') .send({ force: true }) .expect(200); - expect(installResponse.body._meta.install_source).to.be('bundled'); const updateResponse = await supertest @@ -103,8 +102,6 @@ export default function (providerContext: FtrProviderContext) { }); it('should load package archive from bundled package', async () => { - await bundlePackage('nginx-1.2.1'); - const response = await supertest .get(`/api/fleet/epm/packages/nginx/1.2.1?full=true`) .expect(200); @@ -117,7 +114,6 @@ export default function (providerContext: FtrProviderContext) { describe('with registry', () => { it('allows for updating from registry when outdated package is installed from bundled source', async () => { await bundlePackage('nginx-1.1.0'); - const bundledInstallResponse = await supertest .post(`/api/fleet/epm/packages/nginx/1.1.0`) .set('kbn-xsrf', 'xxxx') diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_by_upload.ts b/x-pack/test/fleet_api_integration/apis/epm/install_by_upload.ts index 729a0b4cc5196..e7f3d1d3c0f66 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_by_upload.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_by_upload.ts @@ -16,6 +16,11 @@ import { skipIfNoDockerRegistry, isDockerRegistryEnabledOrSkipped } from '../../ import { setupFleetAndAgents } from '../agents/services'; import { testUsers } from '../test_users'; +/* + * This test takes long to execute because of the wait time between uploads + * The upload endpoint is rate limited with a minimum wait time of 10s + */ + export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); @@ -64,7 +69,7 @@ export default function (providerContext: FtrProviderContext) { await supertest.delete(`/api/fleet/epm/packages/${name}/${version}`).set('kbn-xsrf', 'xxxx'); }; - describe('installs packages from direct upload', async () => { + describe('Installs packages from direct upload', async () => { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); @@ -77,6 +82,8 @@ export default function (providerContext: FtrProviderContext) { async function uploadPackage() { const buf = fs.readFileSync(testPkgArchiveTgz); + // wait 10s before uploading again to avoid getting 429 + await new Promise((resolve) => setTimeout(resolve, 10000)); return await supertest .post(`/api/fleet/epm/packages`) .set('kbn-xsrf', 'xxxx') @@ -93,6 +100,7 @@ export default function (providerContext: FtrProviderContext) { it('should upgrade when uploading a newer zip archive', async () => { await uploadPackage(); + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveZipNewer); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -147,7 +155,23 @@ export default function (providerContext: FtrProviderContext) { expect(epmPackageAssetsRes.hits.total).to.equal(0); }); + it('should get 429 when trying to upload packages too soon', async () => { + await uploadPackage(); + + const buf = fs.readFileSync(testPkgArchiveZipNewer); + const res = await supertest + .post(`/api/fleet/epm/packages`) + .set('kbn-xsrf', 'xxxx') + .type('application/zip') + .send(buf) + .expect(429); + expect((res.error as HTTPError).text).to.equal( + '{"statusCode":429,"error":"Too Many Requests","message":"Too many requests. Please wait 10s before uploading again."}' + ); + }); + it('should install a zip archive correctly and package info should return correctly after validation', async function () { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveZip); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -159,6 +183,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should throw an error if the archive is zip but content type is gzip', async function () { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveZip); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -172,6 +197,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should throw an error if the archive is tar.gz but content type is zip', async function () { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveTgz); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -185,6 +211,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should throw an error if the archive contains two top-level directories', async function () { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveInvalidTwoToplevels); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -198,6 +225,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should throw an error if the archive does not contain a manifest', async function () { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveInvalidNoManifest); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -211,6 +239,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should throw an error if the archive manifest contains invalid YAML', async function () { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveInvalidManifestInvalidYaml); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -224,6 +253,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should throw an error if the archive manifest misses a mandatory field', async function () { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveInvalidManifestMissingField); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -237,6 +267,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should throw an error if the toplevel directory name does not match the package key', async function () { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveInvalidToplevelMismatch); const res = await supertest .post(`/api/fleet/epm/packages`) @@ -250,6 +281,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should not allow users without all access', async () => { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveTgz); await supertestWithoutAuth .post(`/api/fleet/epm/packages`) @@ -261,6 +293,7 @@ export default function (providerContext: FtrProviderContext) { }); it('should allow user with all access', async () => { + await new Promise((resolve) => setTimeout(resolve, 10000)); const buf = fs.readFileSync(testPkgArchiveTgz); await supertestWithoutAuth .post(`/api/fleet/epm/packages`) diff --git a/x-pack/test/fleet_api_integration/apis/epm/remove_legacy_templates.ts b/x-pack/test/fleet_api_integration/apis/epm/remove_legacy_templates.ts index 0ab9e68d3e59a..bce10e14428f7 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/remove_legacy_templates.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/remove_legacy_templates.ts @@ -98,7 +98,7 @@ export default function (providerContext: FtrProviderContext) { await supertest.delete(`/api/fleet/epm/packages/${pkg}/${version}`).set('kbn-xsrf', 'xxxx'); }; - describe('legacy component template removal', async () => { + describe('Legacy component template removal', async () => { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); @@ -137,6 +137,8 @@ export default function (providerContext: FtrProviderContext) { }); await waitUntilLegacyComponentTemplatesCreated(); + // wait 10s before uploading again to avoid getting 429 + await sleep(10000); await installUploadPackage(); const { component_templates: allComponentTemplates } = diff --git a/x-pack/test/monitoring_api_integration/apis/kibana/index.ts b/x-pack/test/monitoring_api_integration/apis/kibana/index.ts index 4409c5a871397..8b6ca6b8e58f1 100644 --- a/x-pack/test/monitoring_api_integration/apis/kibana/index.ts +++ b/x-pack/test/monitoring_api_integration/apis/kibana/index.ts @@ -10,7 +10,7 @@ import { installPackage } from '../../packages'; export default function ({ loadTestFile, getService }: FtrProviderContext) { describe('Kibana', () => { - before(() => installPackage(getService('supertest'), 'kibana')); + before(async () => await installPackage(getService('supertest'), 'kibana')); loadTestFile(require.resolve('./overview')); loadTestFile(require.resolve('./instances')); diff --git a/x-pack/test/monitoring_api_integration/packages.ts b/x-pack/test/monitoring_api_integration/packages.ts index 981845eb460dc..ec9d9911b189f 100644 --- a/x-pack/test/monitoring_api_integration/packages.ts +++ b/x-pack/test/monitoring_api_integration/packages.ts @@ -30,12 +30,14 @@ export const getPackagesArgs = (): string[] => { export const bundledPackagesLocation = path.join(path.dirname(__filename), '/fixtures/packages'); -export function installPackage(supertest: SuperTest.Agent, packageName: SupportedPackage) { +export async function installPackage(supertest: SuperTest.Agent, packageName: SupportedPackage) { const pkg = PACKAGES.find(({ name }) => name === packageName); const request = supertest .post('/api/fleet/epm/packages') .set('kbn-xsrf', 'xxx') .set('content-type', 'application/zip'); + // wait 10s before uploading again to avoid getting 429 from upload endpoint + await new Promise((resolve) => setTimeout(resolve, 10000)); return new Promise((resolve, reject) => { createReadStream(path.join(bundledPackagesLocation, `${pkg!.name}-${pkg!.version}.zip`)) From 5743aa09cf2a598685214fe4af9f3d997f556e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Thu, 6 Jun 2024 18:55:40 +0200 Subject: [PATCH 24/87] [Obs AI Assistant] Use const for function names (#184830) Some of the AI Assistant functions have very generic names. One example is the `context` function. When stumbling upon code like ``` const contextRequest = functionClient.hasFunction('context') ``` ... it is quite difficult to navigate to the context function implementation without knowing it's exact location. Searching for `context` is futile since it's a term used for many different things. Using a constant to refer to a function makes it much easier to navigate to where the function is registered. It also avoids typos but that's a side-effect, not the main motivation for this. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../server/functions/context.ts | 6 ++-- .../functions/get_dataset_info/index.ts | 4 ++- .../server/functions/index.ts | 36 ++++++++++--------- .../server/functions/summarize.ts | 4 ++- .../chat_function_client/index.test.ts | 6 ++-- .../service/chat_function_client/index.ts | 4 ++- .../get_system_message_instructions.ts | 3 +- .../get_context_function_request_if_needed.ts | 5 +-- .../server/service/client/index.test.ts | 11 +++--- .../server/service/client/index.ts | 3 +- .../client/operators/continue_conversation.ts | 3 +- .../public/components/chat/chat_body.test.tsx | 9 ++--- ..._timeline_items_from_conversation.test.tsx | 9 ++--- .../server/functions/changes/index.ts | 4 ++- .../server/functions/query/index.ts | 16 +++++---- .../server/index.ts | 2 ++ 16 files changed, 75 insertions(+), 50 deletions(-) diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/context.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/context.ts index 4a347c2710ef4..4bc32a2330acd 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/context.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/context.ts @@ -26,6 +26,8 @@ import { parseSuggestionScores } from './parse_suggestion_scores'; const MAX_TOKEN_COUNT_FOR_DATA_ON_SCREEN = 1000; +export const CONTEXT_FUNCTION_NAME = 'context'; + export function registerContextFunction({ client, functions, @@ -34,7 +36,7 @@ export function registerContextFunction({ }: FunctionRegistrationParameters & { isKnowledgeBaseAvailable: boolean }) { functions.registerFunction( { - name: 'context', + name: CONTEXT_FUNCTION_NAME, description: 'This function provides context as to what the user is looking at on their screen, and recalled documents from the knowledge base that matches their query', visibility: FunctionVisibility.Internal, @@ -157,7 +159,7 @@ export function registerContextFunction({ .then(({ content, data }) => { subscriber.next( createFunctionResponseMessage({ - name: 'context', + name: CONTEXT_FUNCTION_NAME, content, data, }) diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/get_dataset_info/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/get_dataset_info/index.ts index f016ae126ca53..bac7963cecbdf 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/get_dataset_info/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/get_dataset_info/index.ts @@ -9,13 +9,15 @@ import { FunctionRegistrationParameters } from '..'; import { FunctionVisibility } from '../../../common/functions/types'; import { getRelevantFieldNames } from './get_relevant_field_names'; +export const GET_DATASET_INFO_FUNCTION_NAME = 'get_dataset_info'; + export function registerGetDatasetInfoFunction({ resources, functions, }: FunctionRegistrationParameters) { functions.registerFunction( { - name: 'get_dataset_info', + name: GET_DATASET_INFO_FUNCTION_NAME, visibility: FunctionVisibility.AssistantOnly, description: `Use this function to get information about indices/datasets available and the fields available on them. diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/index.ts index 7f706046a693c..4cf8147d31c71 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/index.ts @@ -6,13 +6,17 @@ */ import dedent from 'dedent'; -import { registerContextFunction } from './context'; -import { registerSummarizationFunction } from './summarize'; +import { CONTEXT_FUNCTION_NAME, registerContextFunction } from './context'; +import { registerSummarizationFunction, SUMMARIZE_FUNCTION_NAME } from './summarize'; import type { RegistrationCallback } from '../service/types'; import { registerElasticsearchFunction } from './elasticsearch'; -import { registerGetDatasetInfoFunction } from './get_dataset_info'; +import { GET_DATASET_INFO_FUNCTION_NAME, registerGetDatasetInfoFunction } from './get_dataset_info'; import { registerKibanaFunction } from './kibana'; import { registerExecuteConnectorFunction } from './execute_connector'; +import { GET_DATA_ON_SCREEN_FUNCTION_NAME } from '../service/chat_function_client'; + +// cannot be imported from x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts due to circular dependency +export const QUERY_FUNCTION_NAME = 'query'; export type FunctionRegistrationParameters = Omit< Parameters[0], @@ -59,30 +63,30 @@ export const registerFunctions: RegistrationCallback = async ({ functions.registerInstruction(({ availableFunctionNames }) => { const instructions: string[] = []; - if (availableFunctionNames.includes('get_dataset_info')) { - instructions.push(`You MUST use the get_dataset_info function ${ - functions.hasFunction('get_apm_dataset_info') ? 'or get_apm_dataset_info' : '' - } function before calling the "query" or "changes" function. + if (availableFunctionNames.includes(GET_DATASET_INFO_FUNCTION_NAME)) { + instructions.push(`You MUST use the "${GET_DATASET_INFO_FUNCTION_NAME}" ${ + functions.hasFunction('get_apm_dataset_info') ? 'or the get_apm_dataset_info' : '' + } function before calling the "${QUERY_FUNCTION_NAME}" or the "changes" functions. - If a function requires an index, you MUST use the results from the dataset info functions.`); + If a function requires an index, you MUST use the results from the dataset info functions.`); } - if (availableFunctionNames.includes('get_data_on_screen')) { - instructions.push(`You have access to data on the screen by calling the "get_data_on_screen" function. - Use it to help the user understand what they are looking at. A short summary of what they are looking at is available in the return of the "context" function. - Data that is compact enough automatically gets included in the response for the "context" function.`); + if (availableFunctionNames.includes(GET_DATA_ON_SCREEN_FUNCTION_NAME)) { + instructions.push(`You have access to data on the screen by calling the "${GET_DATA_ON_SCREEN_FUNCTION_NAME}" function. + Use it to help the user understand what they are looking at. A short summary of what they are looking at is available in the return of the "${CONTEXT_FUNCTION_NAME}" function. + Data that is compact enough automatically gets included in the response for the "${CONTEXT_FUNCTION_NAME}" function.`); } if (isReady) { - if (availableFunctionNames.includes('summarize')) { - instructions.push(`You can use the "summarize" functions to store new information you have learned in a knowledge database. + if (availableFunctionNames.includes(SUMMARIZE_FUNCTION_NAME)) { + instructions.push(`You can use the "${SUMMARIZE_FUNCTION_NAME}" function to store new information you have learned in a knowledge database. Only use this function when the user asks for it. All summaries MUST be created in English, even if the conversation was carried out in a different language.`); } - if (availableFunctionNames.includes('context')) { + if (availableFunctionNames.includes(CONTEXT_FUNCTION_NAME)) { instructions.push( - `Additionally, you can use the "context" function to retrieve relevant information from the knowledge database.` + `Additionally, you can use the "${CONTEXT_FUNCTION_NAME}" function to retrieve relevant information from the knowledge database.` ); } } else { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/summarize.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/summarize.ts index 4ff8e3ee4da91..ff14f5a3d3db3 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/summarize.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/summarize.ts @@ -8,13 +8,15 @@ import type { FunctionRegistrationParameters } from '.'; import { KnowledgeBaseEntryRole } from '../../common'; +export const SUMMARIZE_FUNCTION_NAME = 'summarize'; + export function registerSummarizationFunction({ client, functions, }: FunctionRegistrationParameters) { functions.registerFunction( { - name: 'summarize', + name: SUMMARIZE_FUNCTION_NAME, description: `Use this function to store facts in the knowledge database if the user requests it. You can score the learnings with a confidence metric, whether it is a correction on a previous learning. An embedding will be created that you can recall later with a semantic search. diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.test.ts index bdce24d65d2c7..cbb833d0aeb76 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ import dedent from 'dedent'; -import { ChatFunctionClient } from '.'; +import { ChatFunctionClient, GET_DATA_ON_SCREEN_FUNCTION_NAME } from '.'; import { FunctionVisibility } from '../../../common/functions/types'; describe('chatFunctionClient', () => { @@ -88,7 +88,7 @@ describe('chatFunctionClient', () => { expect(functions[0]).toEqual({ definition: { description: expect.any(String), - name: 'get_data_on_screen', + name: GET_DATA_ON_SCREEN_FUNCTION_NAME, parameters: expect.any(Object), visibility: FunctionVisibility.AssistantOnly, }, @@ -103,7 +103,7 @@ describe('chatFunctionClient', () => { const result = await client.executeFunction({ chat: jest.fn(), - name: 'get_data_on_screen', + name: GET_DATA_ON_SCREEN_FUNCTION_NAME, args: JSON.stringify({ data: ['my_dummy_data'] }), messages: [], signal: new AbortController().signal, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.ts index e882616e202cc..0b0f202e703cd 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/chat_function_client/index.ts @@ -31,6 +31,8 @@ const ajv = new Ajv({ strict: false, }); +export const GET_DATA_ON_SCREEN_FUNCTION_NAME = 'get_data_on_screen'; + export class ChatFunctionClient { private readonly instructions: RegisteredInstruction[] = []; private readonly functionRegistry: FunctionHandlerRegistry = new Map(); @@ -46,7 +48,7 @@ export class ChatFunctionClient { if (allData.length) { this.registerFunction( { - name: 'get_data_on_screen', + name: GET_DATA_ON_SCREEN_FUNCTION_NAME, description: dedent(`Get data that is on the screen: ${allData.map((data) => `${data.name}: ${data.description}`).join('\n')} `), diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/adapters/simulate_function_calling/get_system_message_instructions.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/adapters/simulate_function_calling/get_system_message_instructions.ts index 2bf1052ec30e5..a409a80716320 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/adapters/simulate_function_calling/get_system_message_instructions.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/adapters/simulate_function_calling/get_system_message_instructions.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { CONTEXT_FUNCTION_NAME } from '../../../../functions/context'; import { FunctionDefinition } from '../../../../../common'; import { TOOL_USE_END, TOOL_USE_START } from './constants'; @@ -17,7 +18,7 @@ export function getSystemMessageInstructions({ return `In this environment, you have access to a set of tools you can use to answer the user's question. ${ - functions?.find((fn) => fn.name === 'context') + functions?.find((fn) => fn.name === CONTEXT_FUNCTION_NAME) ? `The "context" tool is ALWAYS used after a user question. Even if it was used before, your job is to answer the last user question, even if the "context" tool was executed after that. Consider the tools you need to answer the user's question.` : '' diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/get_context_function_request_if_needed.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/get_context_function_request_if_needed.ts index 8f05cf144a33b..74cc19d8aa153 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/get_context_function_request_if_needed.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/get_context_function_request_if_needed.ts @@ -8,6 +8,7 @@ import { findLastIndex } from 'lodash'; import { Message, MessageAddEvent, MessageRole } from '../../../common'; import { createFunctionRequestMessage } from '../../../common/utils/create_function_request_message'; +import { CONTEXT_FUNCTION_NAME } from '../../functions/context'; export function getContextFunctionRequestIfNeeded( messages: Message[] @@ -19,14 +20,14 @@ export function getContextFunctionRequestIfNeeded( const hasContextSinceLastUserMessage = messages .slice(indexOfLastUserMessage) - .some((message) => message.message.name === 'context'); + .some((message) => message.message.name === CONTEXT_FUNCTION_NAME); if (hasContextSinceLastUserMessage) { return undefined; } return createFunctionRequestMessage({ - name: 'context', + name: CONTEXT_FUNCTION_NAME, args: { queries: [], categories: [], diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts index add345ffce9c5..829f0097875f8 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts @@ -24,6 +24,7 @@ import { StreamingChatResponseEventType, } from '../../../common/conversation_complete'; import { createFunctionResponseMessage } from '../../../common/utils/create_function_response_message'; +import { CONTEXT_FUNCTION_NAME } from '../../functions/context'; import { ChatFunctionClient } from '../chat_function_client'; import type { KnowledgeBaseService } from '../knowledge_base_service'; import { observableIntoStream } from '../util/observable_into_stream'; @@ -145,7 +146,7 @@ describe('Observability AI Assistant client', () => { functionClientMock.getFunctions.mockReturnValue([]); functionClientMock.hasFunction.mockImplementation((name) => { - return name !== 'context'; + return name !== CONTEXT_FUNCTION_NAME; }); functionClientMock.hasAction.mockReturnValue(false); @@ -1230,7 +1231,7 @@ describe('Observability AI Assistant client', () => { content: '', role: MessageRole.Assistant, function_call: { - name: 'context', + name: CONTEXT_FUNCTION_NAME, arguments: JSON.stringify({ queries: [], categories: [] }), trigger: MessageRole.Assistant, }, @@ -1248,7 +1249,7 @@ describe('Observability AI Assistant client', () => { message: { content: JSON.stringify([{ id: 'my_document', text: 'My document' }]), role: MessageRole.User, - name: 'context', + name: CONTEXT_FUNCTION_NAME, }, }, }); @@ -1440,7 +1441,7 @@ describe('Observability AI Assistant client', () => { it('executes the context function', async () => { expect(functionClientMock.executeFunction).toHaveBeenCalledWith( - expect.objectContaining({ name: 'context' }) + expect.objectContaining({ name: CONTEXT_FUNCTION_NAME }) ); }); @@ -1454,7 +1455,7 @@ describe('Observability AI Assistant client', () => { content: '', role: MessageRole.Assistant, function_call: { - name: 'context', + name: CONTEXT_FUNCTION_NAME, arguments: JSON.stringify({ queries: [], categories: [] }), trigger: MessageRole.Assistant, }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts index 694fbb3233edc..6af7ee9aa36ee 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts @@ -53,6 +53,7 @@ import { type Message, } from '../../../common/types'; import { withoutTokenCountEvents } from '../../../common/utils/without_token_count_events'; +import { CONTEXT_FUNCTION_NAME } from '../../functions/context'; import type { ChatFunctionClient } from '../chat_function_client'; import { KnowledgeBaseEntryOperationType, @@ -271,7 +272,7 @@ export class ObservabilityAIAssistantClient { ]).pipe( switchMap(([messagesWithUpdatedSystemMessage, knowledgeBaseInstructions]) => { // if needed, inject a context function request here - const contextRequest = functionClient.hasFunction('context') + const contextRequest = functionClient.hasFunction(CONTEXT_FUNCTION_NAME) ? getContextFunctionRequestIfNeeded(messagesWithUpdatedSystemMessage) : undefined; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/continue_conversation.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/continue_conversation.ts index ba9e8138fe95a..b7b134afc955c 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/continue_conversation.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/continue_conversation.ts @@ -21,6 +21,7 @@ import { switchMap, throwError, } from 'rxjs'; +import { CONTEXT_FUNCTION_NAME } from '../../../functions/context'; import { createFunctionNotFoundError, Message, MessageRole } from '../../../../common'; import { createFunctionLimitExceededError, @@ -209,7 +210,7 @@ export function continueConversation({ function executeNextStep() { if (isUserMessage) { const operationName = - lastMessage.name && lastMessage.name !== 'context' + lastMessage.name && lastMessage.name !== CONTEXT_FUNCTION_NAME ? `function_response ${lastMessage.name}` : 'user_message'; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/chat/chat_body.test.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/chat/chat_body.test.tsx index cfb85f7945240..e39bcf5d1891e 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/chat/chat_body.test.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/chat/chat_body.test.tsx @@ -6,6 +6,7 @@ */ import { Message } from '@kbn/observability-ai-assistant-plugin/common'; +import { CONTEXT_FUNCTION_NAME } from '@kbn/observability-ai-assistant-plugin/server/functions/context'; import { reverseToLastUserMessage } from './chat_body'; describe('', () => { @@ -38,7 +39,7 @@ describe('', () => { message: { role: 'assistant', function_call: { - name: 'context', + name: CONTEXT_FUNCTION_NAME, arguments: '{"queries":[],"categories":[]}', trigger: 'assistant', }, @@ -48,7 +49,7 @@ describe('', () => { { message: { role: 'user', - name: 'context', + name: CONTEXT_FUNCTION_NAME, content: '[]', }, }, @@ -86,7 +87,7 @@ describe('', () => { message: { role: 'assistant', function_call: { - name: 'context', + name: CONTEXT_FUNCTION_NAME, arguments: '{"queries":[],"categories":[]}', trigger: 'assistant', }, @@ -96,7 +97,7 @@ describe('', () => { { message: { role: 'user', - name: 'context', + name: CONTEXT_FUNCTION_NAME, content: '[]', }, }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/utils/get_timeline_items_from_conversation.test.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/utils/get_timeline_items_from_conversation.test.tsx index e73555540b1e8..6fb7e1a323d08 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/utils/get_timeline_items_from_conversation.test.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/utils/get_timeline_items_from_conversation.test.tsx @@ -12,6 +12,7 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { ChatState, Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/public'; import { createMockChatService } from './create_mock_chat_service'; import { KibanaContextProvider } from '@kbn/triggers-actions-ui-plugin/public/common/lib/kibana'; +import { CONTEXT_FUNCTION_NAME } from '@kbn/observability-ai-assistant-plugin/server/functions/context'; const mockChatService = createMockChatService(); @@ -135,7 +136,7 @@ describe('getTimelineItemsFromConversation', () => { message: { role: MessageRole.Assistant, function_call: { - name: 'context', + name: CONTEXT_FUNCTION_NAME, arguments: JSON.stringify({ queries: [], contexts: [] }), trigger: MessageRole.Assistant, }, @@ -145,7 +146,7 @@ describe('getTimelineItemsFromConversation', () => { '@timestamp': new Date().toISOString(), message: { role: MessageRole.User, - name: 'context', + name: CONTEXT_FUNCTION_NAME, content: JSON.stringify([]), }, }, @@ -430,7 +431,7 @@ describe('getTimelineItemsFromConversation', () => { message: { role: MessageRole.Assistant, function_call: { - name: 'context', + name: CONTEXT_FUNCTION_NAME, arguments: JSON.stringify({ queries: [], contexts: [] }), trigger: MessageRole.User, }, @@ -440,7 +441,7 @@ describe('getTimelineItemsFromConversation', () => { '@timestamp': new Date().toISOString(), message: { role: MessageRole.User, - name: 'context', + name: CONTEXT_FUNCTION_NAME, content: JSON.stringify([]), }, }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/changes/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/changes/index.ts index 89ebfa90cb774..987414214a17b 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/changes/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/changes/index.ts @@ -17,6 +17,8 @@ import { import { getMetricChanges } from './get_metric_changes'; import { getLogChanges } from './get_log_changes'; +export const CHANGES_FUNCTION_NAME = 'changes'; + export function registerChangesFunction({ functions, resources: { @@ -26,7 +28,7 @@ export function registerChangesFunction({ }: FunctionRegistrationParameters) { functions.registerFunction( { - name: 'changes', + name: CHANGES_FUNCTION_NAME, description: 'Returns change points like spikes and dips for logs and metrics.', parameters: changesFunctionParameters, }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts index 92d79053ad4af..8a81d9ae32123 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts @@ -26,6 +26,8 @@ import type { FunctionRegistrationParameters } from '..'; import { correctCommonEsqlMistakes } from './correct_common_esql_mistakes'; import { runAndValidateEsqlQuery } from './validate_esql_query'; +export const QUERY_FUNCTION_NAME = 'query'; + const readFile = promisify(Fs.readFile); const readdir = promisify(Fs.readdir); @@ -69,8 +71,8 @@ const loadEsqlDocs = once(async () => { export function registerQueryFunction({ functions, resources }: FunctionRegistrationParameters) { functions.registerInstruction(({ availableFunctionNames }) => - availableFunctionNames.includes('query') - ? `You MUST use the "query" function when the user wants to: + availableFunctionNames.includes(QUERY_FUNCTION_NAME) + ? `You MUST use the "${QUERY_FUNCTION_NAME}" function when the user wants to: - visualize data - run any arbitrary query - breakdown or filter ES|QL queries that are displayed on the current page @@ -78,11 +80,11 @@ export function registerQueryFunction({ functions, resources }: FunctionRegistra - asks general questions about ES|QL DO NOT UNDER ANY CIRCUMSTANCES generate ES|QL queries or explain anything about the ES|QL query language yourself. - DO NOT UNDER ANY CIRCUMSTANCES try to correct an ES|QL query yourself - always use the "query" function for this. + DO NOT UNDER ANY CIRCUMSTANCES try to correct an ES|QL query yourself - always use the "${QUERY_FUNCTION_NAME}" function for this. If the user asks for a query, and one of the dataset info functions was called and returned no results, you should still call the query function to generate an example query. - Even if the "context" function was used before that, follow it up with the "query" function. If a query fails, do not attempt to correct it yourself. Again you should call the "query" function, + Even if the "${QUERY_FUNCTION_NAME}" function was used before that, follow it up with the "${QUERY_FUNCTION_NAME}" function. If a query fails, do not attempt to correct it yourself. Again you should call the "${QUERY_FUNCTION_NAME}" function, even if it has been called before. When the "visualize_query" function has been called, a visualization has been displayed to the user. DO NOT UNDER ANY CIRCUMSTANCES follow up a "visualize_query" function call with your own visualization attempt. @@ -132,7 +134,7 @@ export function registerQueryFunction({ functions, resources }: FunctionRegistra ); functions.registerFunction( { - name: 'query', + name: QUERY_FUNCTION_NAME, description: `This function generates, executes and/or visualizes a query based on the user's request. It also explains how ES|QL works and how to convert queries from one language to another. Make sure you call one of the get_dataset functions first if you need index or field names. This function takes no input.`, visibility: FunctionVisibility.AssistantOnly, }, @@ -159,7 +161,7 @@ export function registerQueryFunction({ functions, resources }: FunctionRegistra await chat('classify_esql', { messages: withEsqlSystemMessage().concat( createFunctionResponseMessage({ - name: 'query', + name: QUERY_FUNCTION_NAME, content: {}, }).message, { @@ -323,7 +325,7 @@ export function registerQueryFunction({ functions, resources }: FunctionRegistra } const queryFunctionResponseMessage = createFunctionResponseMessage({ - name: 'query', + name: QUERY_FUNCTION_NAME, content: {}, data: { // add the included docs for debugging diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/index.ts index 36217f5a762e5..bf14959a2fba9 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/index.ts @@ -8,6 +8,8 @@ import type { PluginConfigDescriptor, PluginInitializerContext } from '@kbn/core/server'; import type { ObservabilityAIAssistantAppConfig } from './config'; +export { CHANGES_FUNCTION_NAME } from './functions/changes'; +export { QUERY_FUNCTION_NAME } from './functions/query'; import { config as configSchema } from './config'; export type { ObservabilityAIAssistantAppServerStart, From 7d8fc904911453927e6691773498a3276a7f8f62 Mon Sep 17 00:00:00 2001 From: Rachel Shen Date: Thu, 6 Jun 2024 10:57:55 -0600 Subject: [PATCH 25/87] [Share Modal][Fix] Serverless environments customizations (#184700) ## Summary Closes [184539](https://github.com/elastic/kibana/issues/184539) There is a misleading message for serverless deployments that do not do upgrades manually. This PR removes the callout in serverless environments. Also copy post url needs to be removed since there are no public apis for CSV reports in serverless. cc @tsullivan --- .../share/public/components/context/index.tsx | 1 + .../components/tabs/export/export_content.tsx | 52 ++++++++++++------- .../public/components/tabs/export/index.tsx | 3 +- .../public/services/share_menu_manager.tsx | 3 ++ src/plugins/share/public/types.ts | 1 + 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/plugins/share/public/components/context/index.tsx b/src/plugins/share/public/components/context/index.tsx index 1426bd42c805a..46cdea37f002f 100644 --- a/src/plugins/share/public/components/context/index.tsx +++ b/src/plugins/share/public/components/context/index.tsx @@ -31,6 +31,7 @@ export interface IShareContext extends ShareContext { isEmbedded: boolean; theme: ThemeServiceSetup; i18n: I18nStart; + publicAPIEnabled?: boolean; anchorElement?: HTMLElement; } diff --git a/src/plugins/share/public/components/tabs/export/export_content.tsx b/src/plugins/share/public/components/tabs/export/export_content.tsx index b979a61c5398c..b1106b7df7774 100644 --- a/src/plugins/share/public/components/tabs/export/export_content.tsx +++ b/src/plugins/share/public/components/tabs/export/export_content.tsx @@ -33,9 +33,16 @@ type ExportProps = Pick { +const ExportContentUi = ({ + isDirty, + aggregateReportTypes, + intl, + onClose, + publicAPIEnabled, +}: ExportProps) => { const [isCreatingExport, setIsCreatingExport] = useState(false); const [usePrintLayout, setPrintLayout] = useState(false); @@ -116,7 +123,7 @@ const ExportContentUi = ({ isDirty, aggregateReportTypes, intl, onClose }: Expor }, [usePrintLayout, renderLayoutOptionSwitch, handlePrintLayoutChange]); const showCopyURLButton = useCallback(() => { - if (renderCopyURLButton) + if (renderCopyURLButton && publicAPIEnabled) return ( @@ -151,7 +158,7 @@ const ExportContentUi = ({ isDirty, aggregateReportTypes, intl, onClose }: Expor ); - }, [absoluteUrl, renderCopyURLButton]); + }, [absoluteUrl, renderCopyURLButton, publicAPIEnabled]); const renderGenerateReportButton = useCallback(() => { return ( @@ -185,6 +192,28 @@ const ExportContentUi = ({ isDirty, aggregateReportTypes, intl, onClose }: Expor } }; + const renderHelpText = () => { + const showHelpText = publicAPIEnabled && isDirty; + return ( + showHelpText && ( + <> + + + } + > + + + + ) + ); + }; + return ( <> @@ -192,22 +221,7 @@ const ExportContentUi = ({ isDirty, aggregateReportTypes, intl, onClose }: Expor <>{helpText} <>{renderRadioOptions()} - {isDirty && ( - <> - - - } - > - - - - )} + {renderHelpText()} diff --git a/src/plugins/share/public/components/tabs/export/index.tsx b/src/plugins/share/public/components/tabs/export/index.tsx index 28066ee3d65c6..68a329c0a54a5 100644 --- a/src/plugins/share/public/components/tabs/export/index.tsx +++ b/src/plugins/share/public/components/tabs/export/index.tsx @@ -15,7 +15,7 @@ import { useShareTabsContext, type ShareMenuItemV2 } from '../../context'; type IExportTab = IModalTabDeclaration; const ExportTabContent = () => { - const { shareMenuItems, objectType, isDirty, onClose } = useShareTabsContext()!; + const { shareMenuItems, objectType, isDirty, onClose, publicAPIEnabled } = useShareTabsContext()!; return ( { onClose={onClose} // we are guaranteed that shareMenuItems will be a ShareMenuItem V2 variant aggregateReportTypes={shareMenuItems as unknown as ShareMenuItemV2[]} + publicAPIEnabled={publicAPIEnabled ?? true} /> ); }; diff --git a/src/plugins/share/public/services/share_menu_manager.tsx b/src/plugins/share/public/services/share_menu_manager.tsx index 1bec2d9f6416e..0f58e875cfcd5 100644 --- a/src/plugins/share/public/services/share_menu_manager.tsx +++ b/src/plugins/share/public/services/share_menu_manager.tsx @@ -52,6 +52,7 @@ export class ShareMenuManager { overlays: core.overlays, i18n: core.i18n, toasts: core.notifications.toasts, + publicAPIEnabled: !disableEmbed, }); }, }; @@ -86,6 +87,7 @@ export class ShareMenuManager { isDirty, toasts, delegatedShareUrlHandler, + publicAPIEnabled, }: ShowShareMenuOptions & { anchorElement: HTMLElement; menuItems: ShareMenuItem[]; @@ -111,6 +113,7 @@ export class ShareMenuManager { toMountPoint( { embedUrlParamExtensions?: UrlParamExtension[]; snapshotShareWarning?: string; onClose?: () => void; + publicAPIEnabled?: boolean; } export interface ClientConfigType { From 667a9d36910e17eb8cb2a1f75134d4a8e1fd8949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Thu, 6 Jun 2024 18:06:21 +0100 Subject: [PATCH 26/87] [Stateful sidenav] Add cloud yml setting for onboarding default solution (#184808) --- .../test_suites/core_plugins/rendering.ts | 1 + x-pack/plugins/cloud/common/index.ts | 8 ++++ .../parse_onboarding_default_solution.test.ts | 33 ++++++++++++++++ .../parse_onboarding_default_solution.ts | 39 +++++++++++++++++++ x-pack/plugins/cloud/common/types.ts | 8 ++++ x-pack/plugins/cloud/public/mocks.tsx | 1 + x-pack/plugins/cloud/public/plugin.test.ts | 9 +++++ x-pack/plugins/cloud/public/plugin.tsx | 10 ++++- x-pack/plugins/cloud/public/types.ts | 10 +++++ .../server/__snapshots__/plugin.test.ts.snap | 3 ++ x-pack/plugins/cloud/server/config.ts | 8 ++++ x-pack/plugins/cloud/server/mocks.ts | 1 + x-pack/plugins/cloud/server/plugin.test.ts | 9 +++++ x-pack/plugins/cloud/server/plugin.ts | 14 +++++++ .../get_cloud_enterprise_search_host.test.ts | 4 ++ .../plugins/fleet/.storybook/context/cloud.ts | 1 + .../fleet_server_host.test.ts | 5 +++ 17 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/cloud/common/index.ts create mode 100644 x-pack/plugins/cloud/common/parse_onboarding_default_solution.test.ts create mode 100644 x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts create mode 100644 x-pack/plugins/cloud/common/types.ts diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index df4353beb569c..7ccbc90d8760e 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -256,6 +256,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.cloud.serverless.project_id (string)', 'xpack.cloud.serverless.project_name (string)', 'xpack.cloud.serverless.project_type (string)', + 'xpack.cloud.onboarding.default_solution (string)', 'xpack.discoverEnhanced.actions.exploreDataInChart.enabled (boolean)', 'xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled (boolean)', 'xpack.fleet.agents.enabled (boolean)', diff --git a/x-pack/plugins/cloud/common/index.ts b/x-pack/plugins/cloud/common/index.ts new file mode 100644 index 0000000000000..4aa6ce8d5edf0 --- /dev/null +++ b/x-pack/plugins/cloud/common/index.ts @@ -0,0 +1,8 @@ +/* + * 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 type { OnBoardingDefaultSolution } from './types'; diff --git a/x-pack/plugins/cloud/common/parse_onboarding_default_solution.test.ts b/x-pack/plugins/cloud/common/parse_onboarding_default_solution.test.ts new file mode 100644 index 0000000000000..de8b305ee452b --- /dev/null +++ b/x-pack/plugins/cloud/common/parse_onboarding_default_solution.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { parseOnboardingSolution } from './parse_onboarding_default_solution'; + +describe('parseOnboardingSolution', () => { + it('should return undefined if there is no default solution defined', () => { + expect(parseOnboardingSolution()).toBeUndefined(); + }); + + it('should map correctly the cloud values to the Kibana values, regardless of case', () => { + [ + ['elasticsearch', 'es'], + ['Elasticsearch', 'es'], + ['observability', 'oblt'], + ['Observability', 'oblt'], + ['security', 'security'], + ['Security', 'security'], + ].forEach(([cloudValue, kibanaValue]) => { + expect(parseOnboardingSolution(cloudValue)).toBe(kibanaValue); + expect(parseOnboardingSolution(cloudValue.toUpperCase())).toBe(kibanaValue); + expect(parseOnboardingSolution(cloudValue.toLowerCase())).toBe(kibanaValue); + }); + }); + + it('should return undefined for unknown values', () => { + expect(parseOnboardingSolution('unknown')).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts b/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts new file mode 100644 index 0000000000000..e5938f77af92f --- /dev/null +++ b/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts @@ -0,0 +1,39 @@ +/* + * 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 { OnBoardingDefaultSolution } from './types'; + +/** + * Cloud does not type the value of the "use case" that is set during onboarding for a deployment. Any string can + * be passed. This function maps the known values to the Kibana values. + * + * @param value The solution value set by Cloud. + * @returns The default solution value for onboarding that matches Kibana naming. + */ +export function parseOnboardingSolution(value?: string): OnBoardingDefaultSolution | undefined { + if (!value) return; + + const solutions: Array<{ + cloudValue: 'elasticsearch' | 'observability' | 'security'; + kibanaValue: OnBoardingDefaultSolution; + }> = [ + { + cloudValue: 'elasticsearch', + kibanaValue: 'es', + }, + { + cloudValue: 'observability', + kibanaValue: 'oblt', + }, + { + cloudValue: 'security', + kibanaValue: 'security', + }, + ]; + + return solutions.find(({ cloudValue }) => value.toLowerCase() === cloudValue)?.kibanaValue; +} diff --git a/x-pack/plugins/cloud/common/types.ts b/x-pack/plugins/cloud/common/types.ts new file mode 100644 index 0000000000000..ac4593fd0e259 --- /dev/null +++ b/x-pack/plugins/cloud/common/types.ts @@ -0,0 +1,8 @@ +/* + * 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 type OnBoardingDefaultSolution = 'es' | 'oblt' | 'security'; diff --git a/x-pack/plugins/cloud/public/mocks.tsx b/x-pack/plugins/cloud/public/mocks.tsx index 8bd4a933a0f1b..dd5c5eced618a 100644 --- a/x-pack/plugins/cloud/public/mocks.tsx +++ b/x-pack/plugins/cloud/public/mocks.tsx @@ -26,6 +26,7 @@ function createSetupMock(): jest.Mocked { isElasticStaffOwned: true, trialEndDate: new Date('2020-10-01T14:13:12Z'), registerCloudService: jest.fn(), + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, diff --git a/x-pack/plugins/cloud/public/plugin.test.ts b/x-pack/plugins/cloud/public/plugin.test.ts index 99e6f97946cca..61ed450324637 100644 --- a/x-pack/plugins/cloud/public/plugin.test.ts +++ b/x-pack/plugins/cloud/public/plugin.test.ts @@ -122,6 +122,15 @@ describe('Cloud Plugin', () => { expect(decodeCloudIdMock).toHaveBeenCalledWith('cloudId', expect.any(Object)); }); + it('exposes `onboarding.default_solution`', () => { + const { setup } = setupPlugin({ + onboarding: { + default_solution: 'Elasticsearch', + }, + }); + expect(setup.onboarding.defaultSolution).toBe('es'); + }); + describe('isServerlessEnabled', () => { it('is `true` when `serverless.projectId` is set', () => { const { setup } = setupPlugin({ diff --git a/x-pack/plugins/cloud/public/plugin.tsx b/x-pack/plugins/cloud/public/plugin.tsx index f0a561194b562..0d071900418c3 100644 --- a/x-pack/plugins/cloud/public/plugin.tsx +++ b/x-pack/plugins/cloud/public/plugin.tsx @@ -8,13 +8,15 @@ import React, { FC, PropsWithChildren } from 'react'; import type { Logger } from '@kbn/logging'; import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; + import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context'; import { getIsCloudEnabled } from '../common/is_cloud_enabled'; import { parseDeploymentIdFromDeploymentUrl } from '../common/parse_deployment_id_from_deployment_url'; import { CLOUD_SNAPSHOTS_PATH } from '../common/constants'; import { decodeCloudId, type DecodedCloudId } from '../common/decode_cloud_id'; -import type { CloudSetup, CloudStart } from './types'; import { getFullCloudUrl } from '../common/utils'; +import { parseOnboardingSolution } from '../common/parse_onboarding_default_solution'; +import type { CloudSetup, CloudStart } from './types'; import { getSupportUrl } from './utils'; export interface CloudConfigType { @@ -31,6 +33,9 @@ export interface CloudConfigType { performance_url?: string; trial_end_date?: string; is_elastic_staff_owned?: boolean; + onboarding?: { + default_solution?: string; + }; serverless?: { project_id: string; project_name?: string; @@ -95,6 +100,9 @@ export class CloudPlugin implements Plugin { trialEndDate: trialEndDate ? new Date(trialEndDate) : undefined, isElasticStaffOwned, isCloudEnabled: this.isCloudEnabled, + onboarding: { + defaultSolution: parseOnboardingSolution(this.config.onboarding?.default_solution), + }, isServerlessEnabled: this.isServerlessEnabled, serverless: { projectId: this.config.serverless?.project_id, diff --git a/x-pack/plugins/cloud/public/types.ts b/x-pack/plugins/cloud/public/types.ts index 8de4f226beea4..a7e34c79a8505 100644 --- a/x-pack/plugins/cloud/public/types.ts +++ b/x-pack/plugins/cloud/public/types.ts @@ -6,6 +6,7 @@ */ import type { FC, PropsWithChildren } from 'react'; +import type { OnBoardingDefaultSolution } from '../common'; export interface CloudStart { /** @@ -174,6 +175,15 @@ export interface CloudSetup { * @param contextProvider The React component from the Service Provider. */ registerCloudService: (contextProvider: FC) => void; + /** + * Onboarding configuration + */ + onboarding: { + /** + * The default solution selected during onboarding. + */ + defaultSolution?: OnBoardingDefaultSolution; + }; /** * `true` when running on Serverless Elastic Cloud * Note that `isCloudEnabled` will always be true when `isServerlessEnabled` is. diff --git a/x-pack/plugins/cloud/server/__snapshots__/plugin.test.ts.snap b/x-pack/plugins/cloud/server/__snapshots__/plugin.test.ts.snap index c1fbbc93e96b5..41002d0c48e6b 100644 --- a/x-pack/plugins/cloud/server/__snapshots__/plugin.test.ts.snap +++ b/x-pack/plugins/cloud/server/__snapshots__/plugin.test.ts.snap @@ -17,6 +17,9 @@ Object { "isElasticStaffOwned": undefined, "isServerlessEnabled": false, "kibanaUrl": undefined, + "onboarding": Object { + "defaultSolution": undefined, + }, "projectsUrl": "https://cloud.elastic.co/projects/", "serverless": Object { "projectId": undefined, diff --git a/x-pack/plugins/cloud/server/config.ts b/x-pack/plugins/cloud/server/config.ts index 39babd548d99a..de4ebd94b6f2b 100644 --- a/x-pack/plugins/cloud/server/config.ts +++ b/x-pack/plugins/cloud/server/config.ts @@ -33,6 +33,11 @@ const configSchema = schema.object({ projects_url: offeringBasedSchema({ serverless: schema.string({ defaultValue: '/projects/' }) }), trial_end_date: schema.maybe(schema.string()), is_elastic_staff_owned: schema.maybe(schema.boolean()), + onboarding: schema.maybe( + schema.object({ + default_solution: schema.maybe(schema.string()), + }) + ), serverless: schema.maybe( schema.object( { @@ -68,6 +73,9 @@ export const config: PluginConfigDescriptor = { project_name: true, project_type: true, }, + onboarding: { + default_solution: true, + }, }, schema: configSchema, }; diff --git a/x-pack/plugins/cloud/server/mocks.ts b/x-pack/plugins/cloud/server/mocks.ts index 78ef284a5c949..e77f58902bf3e 100644 --- a/x-pack/plugins/cloud/server/mocks.ts +++ b/x-pack/plugins/cloud/server/mocks.ts @@ -25,6 +25,7 @@ function createSetupMock(): jest.Mocked { url: undefined, secretToken: undefined, }, + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, diff --git a/x-pack/plugins/cloud/server/plugin.test.ts b/x-pack/plugins/cloud/server/plugin.test.ts index d13e04ca1138a..f2ef8375b417e 100644 --- a/x-pack/plugins/cloud/server/plugin.test.ts +++ b/x-pack/plugins/cloud/server/plugin.test.ts @@ -98,6 +98,15 @@ describe('Cloud Plugin', () => { expect(decodeCloudIdMock).toHaveBeenCalledWith('cloudId', expect.any(Object)); }); + it('exposes `onboarding.default_solution`', () => { + const { setup } = setupPlugin({ + onboarding: { + default_solution: 'Elasticsearch', + }, + }); + expect(setup.onboarding.defaultSolution).toBe('es'); + }); + describe('isServerlessEnabled', () => { it('is `true` when `serverless.projectId` is set', () => { const { setup } = setupPlugin({ diff --git a/x-pack/plugins/cloud/server/plugin.ts b/x-pack/plugins/cloud/server/plugin.ts index 322794b11fa21..d8d5d397655e3 100644 --- a/x-pack/plugins/cloud/server/plugin.ts +++ b/x-pack/plugins/cloud/server/plugin.ts @@ -11,9 +11,11 @@ import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context'; import type { CloudConfigType } from './config'; import { registerCloudUsageCollector } from './collectors'; +import type { OnBoardingDefaultSolution } from '../common'; import { getIsCloudEnabled } from '../common/is_cloud_enabled'; import { parseDeploymentIdFromDeploymentUrl } from '../common/parse_deployment_id_from_deployment_url'; import { decodeCloudId, DecodedCloudId } from '../common/decode_cloud_id'; +import { parseOnboardingSolution } from '../common/parse_onboarding_default_solution'; import { getFullCloudUrl } from '../common/utils'; import { readInstanceSizeMb } from './env'; @@ -88,6 +90,15 @@ export interface CloudSetup { url?: string; secretToken?: string; }; + /** + * Onboarding configuration. + */ + onboarding: { + /** + * The default solution selected during onboarding. + */ + defaultSolution?: OnBoardingDefaultSolution; + }; /** * `true` when running on Serverless Elastic Cloud * Note that `isCloudEnabled` will always be true when `isServerlessEnabled` is. @@ -188,6 +199,9 @@ export class CloudPlugin implements Plugin { url: this.config.apm?.url, secretToken: this.config.apm?.secret_token, }, + onboarding: { + defaultSolution: parseOnboardingSolution(this.config.onboarding?.default_solution), + }, isServerlessEnabled, serverless: { projectId, diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/get_cloud_enterprise_search_host/get_cloud_enterprise_search_host.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/get_cloud_enterprise_search_host/get_cloud_enterprise_search_host.test.ts index 06d07f12668ee..71b413b487090 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/get_cloud_enterprise_search_host/get_cloud_enterprise_search_host.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/get_cloud_enterprise_search_host/get_cloud_enterprise_search_host.test.ts @@ -15,6 +15,7 @@ const defaultPortCloud = { cloudHost: 'us-central1.gcp.cloud.es.io', cloudDefaultPort: '443', registerCloudService: jest.fn(), + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, @@ -29,6 +30,7 @@ const customPortCloud = { cloudHost: 'us-central1.gcp.cloud.es.io', cloudDefaultPort: '9243', registerCloudService: jest.fn(), + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, @@ -39,6 +41,7 @@ const missingDeploymentIdCloud = { 'dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA=', isCloudEnabled: true, registerCloudService: jest.fn(), + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, @@ -48,6 +51,7 @@ const noCloud = { cloudId: undefined, isCloudEnabled: false, registerCloudService: jest.fn(), + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, diff --git a/x-pack/plugins/fleet/.storybook/context/cloud.ts b/x-pack/plugins/fleet/.storybook/context/cloud.ts index 9acbbd221059b..00efa8702ac16 100644 --- a/x-pack/plugins/fleet/.storybook/context/cloud.ts +++ b/x-pack/plugins/fleet/.storybook/context/cloud.ts @@ -18,6 +18,7 @@ export const getCloud = ({ isCloudEnabled }: { isCloudEnabled: boolean }) => { profileUrl: 'https://profile.url', snapshotsUrl: 'https://snapshots.url', registerCloudService: () => {}, + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/fleet_server_host.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration/fleet_server_host.test.ts index 22651dfae1405..de7578129a09b 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/fleet_server_host.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/fleet_server_host.test.ts @@ -159,6 +159,7 @@ describe('getCloudFleetServersHosts', () => { deploymentId: 'deployment-id-1', cloudHost: 'us-east-1.aws.found.io', apm: {}, + onboarding: {}, isServerlessEnabled: true, serverless: { projectId: undefined, @@ -176,6 +177,7 @@ describe('getCloudFleetServersHosts', () => { deploymentId: 'deployment-id-1', cloudHost: 'us-east-1.aws.found.io', apm: {}, + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, @@ -198,6 +200,7 @@ describe('getCloudFleetServersHosts', () => { cloudHost: 'test.fr', cloudDefaultPort: '9243', apm: {}, + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, @@ -233,6 +236,7 @@ describe('createCloudFleetServerHostIfNeeded', () => { isCloudEnabled: true, deploymentId: 'deployment-id-1', apm: {}, + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, @@ -256,6 +260,7 @@ describe('createCloudFleetServerHostIfNeeded', () => { deploymentId: 'deployment-id-1', cloudHost: 'us-east-1.aws.found.io', apm: {}, + onboarding: {}, isServerlessEnabled: false, serverless: { projectId: undefined, From 9a4ceaf59de69ebf349a389c83ffea67e8bb187d Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Thu, 6 Jun 2024 12:50:41 -0500 Subject: [PATCH 27/87] [Security Solution][Alert details] - fix timeline osquery flyout showm behind (#184951) --- .../components/osquery/osquery_flyout.tsx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_flyout.tsx b/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_flyout.tsx index b4758bf79616d..d08d405d5d674 100644 --- a/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_flyout.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { EuiFlyout, @@ -13,6 +13,7 @@ import { EuiFlyoutBody, EuiFlyoutHeader, EuiTitle, + useEuiTheme, useGeneratedHtmlId, } from '@elastic/eui'; import { useQueryClient } from '@tanstack/react-query'; @@ -46,6 +47,14 @@ const OsqueryFlyoutComponent: React.FC = ({ onClose, ecsData, }) => { + const { euiTheme } = useEuiTheme(); + + // we need this flyout to be above the timeline flyout (which has a z-index of 1002) + const maskProps = useMemo( + () => ({ style: `z-index: ${(euiTheme.levels.flyout as number) + 3}` }), + [euiTheme.levels.flyout] + ); + const { services: { osquery }, } = useKibana(); @@ -63,7 +72,13 @@ const OsqueryFlyoutComponent: React.FC = ({ if (osquery?.OsqueryAction) { return ( - +

{ACTION_OSQUERY}

From 1ff87eb551ef75fd6c35cbcb2bb5cbc0253aeff4 Mon Sep 17 00:00:00 2001 From: honeyn303 <117302426+honeyn303@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:52:35 +0200 Subject: [PATCH 28/87] Gemini connector integration (#183668) --- .github/CODEOWNERS | 5 + docs/management/action-types.asciidoc | 4 + .../connectors/action-types/gemini.asciidoc | 74 ++++ .../connectors/images/gemini-connector.png | Bin 0 -> 265115 bytes .../connectors/images/gemini-params.png | Bin 0 -> 196522 bytes docs/management/connectors/index.asciidoc | 1 + docs/settings/alert-action-settings.asciidoc | 7 +- package.json | 1 + .../impl/mock/connectors.ts | 10 + .../docs/openapi/bundled_serverless.json | 167 ++++++++ ...connector_types_generativeai_response.yaml | 10 + .../connector_response_properties.yaml | 2 + .../components/schemas/connector_types.yaml | 1 + .../schemas/create_connector_request.yaml | 2 + .../schemas/update_connector_request.yaml | 1 + .../connector_types.test.ts.snap | 365 +++++++++++++++++ .../mocks/connector_types.ts | 1 + .../server/lib/gen_ai_token_tracking.test.ts | 53 +++ .../server/lib/gen_ai_token_tracking.ts | 22 +- .../lib/get_gcp_oauth_access_token.test.ts | 172 ++++++++ .../server/lib/get_gcp_oauth_access_token.ts | 89 ++++ .../common/gemini/constants.ts | 27 ++ .../stack_connectors/common/gemini/schema.ts | 59 +++ .../stack_connectors/common/gemini/types.ts | 25 ++ .../connector_types/gemini/connector.test.tsx | 203 ++++++++++ .../connector_types/gemini/connector.tsx | 34 ++ .../connector_types/gemini/constants.tsx | 157 +++++++ .../connector_types/gemini/dashboard_link.tsx | 51 +++ .../connector_types/gemini/gemini.test.tsx | 85 ++++ .../public/connector_types/gemini/gemini.tsx | 62 +++ .../public/connector_types/gemini/index.ts | 8 + .../public/connector_types/gemini/logo.tsx | 35 ++ .../connector_types/gemini/params.test.tsx | 206 ++++++++++ .../public/connector_types/gemini/params.tsx | 124 ++++++ .../connector_types/gemini/translations.ts | 109 +++++ .../public/connector_types/gemini/types.ts | 28 ++ .../public/connector_types/index.ts | 2 + .../lib/gen_ai/use_get_dashboard.ts | 13 +- .../connector_types/gemini/gemini.test.ts | 192 +++++++++ .../server/connector_types/gemini/gemini.ts | 188 +++++++++ .../connector_types/gemini/index.test.ts | 89 ++++ .../server/connector_types/gemini/index.ts | 53 +++ .../connector_types/gemini/render.test.ts | 52 +++ .../server/connector_types/gemini/render.ts | 27 ++ .../server/connector_types/index.ts | 2 + .../lib/gen_ai/create_gen_ai_dashboard.ts | 2 +- .../lib/gen_ai/gen_ai_dashboard.ts | 42 +- .../stack_connectors/server/plugin.test.ts | 11 +- .../server/gemini_simulation.ts | 53 +++ .../tests/actions/connector_types/gemini.ts | 382 ++++++++++++++++++ .../check_registered_connector_types.ts | 1 + .../check_registered_task_types.ts | 1 + .../configs/ess.config.ts | 2 +- yarn.lock | 69 +++- 54 files changed, 3353 insertions(+), 28 deletions(-) create mode 100644 docs/management/connectors/action-types/gemini.asciidoc create mode 100644 docs/management/connectors/images/gemini-connector.png create mode 100644 docs/management/connectors/images/gemini-params.png create mode 100644 x-pack/plugins/actions/server/lib/get_gcp_oauth_access_token.test.ts create mode 100644 x-pack/plugins/actions/server/lib/get_gcp_oauth_access_token.ts create mode 100644 x-pack/plugins/stack_connectors/common/gemini/constants.ts create mode 100644 x-pack/plugins/stack_connectors/common/gemini/schema.ts create mode 100644 x-pack/plugins/stack_connectors/common/gemini/types.ts create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/connector.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/connector.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/constants.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/dashboard_link.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/gemini.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/gemini.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/index.ts create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/logo.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/params.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/params.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/translations.ts create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/gemini/types.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/gemini/index.test.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/gemini/index.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/gemini/render.test.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/gemini/render.ts create mode 100644 x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/gemini_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/gemini.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 322780e137b67..5f0a5a3f4bc3d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1497,6 +1497,11 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/stack_connectors/server/connector_types/bedrock @elastic/security-generative-ai /x-pack/plugins/stack_connectors/common/bedrock @elastic/security-generative-ai +# Gemini +/x-pack/plugins/stack_connectors/public/connector_types/gemini @elastic/security-generative-ai +/x-pack/plugins/stack_connectors/server/connector_types/gemini @elastic/security-generative-ai +/x-pack/plugins/stack_connectors/common/gemini @elastic/security-generative-ai + ## Defend Workflows owner connectors /x-pack/plugins/stack_connectors/public/connector_types/sentinelone @elastic/security-defend-workflows /x-pack/plugins/stack_connectors/server/connector_types/sentinelone @elastic/security-defend-workflows diff --git a/docs/management/action-types.asciidoc b/docs/management/action-types.asciidoc index 0d8f43925a1fc..d1dc68045110b 100644 --- a/docs/management/action-types.asciidoc +++ b/docs/management/action-types.asciidoc @@ -20,6 +20,10 @@ a| <> | Send a request to D3 Security. +a| <> + +| Send a request to {gemini}. + a| <> | Send email from your server. diff --git a/docs/management/connectors/action-types/gemini.asciidoc b/docs/management/connectors/action-types/gemini.asciidoc new file mode 100644 index 0000000000000..d1693f0b5ec28 --- /dev/null +++ b/docs/management/connectors/action-types/gemini.asciidoc @@ -0,0 +1,74 @@ +[[gemini-action-type]] +== {gemini} connector and action +++++ +{gemini} +++++ +:frontmatter-description: Add a connector that can send requests to {gemini}. +:frontmatter-tags-products: [kibana] +:frontmatter-tags-content-type: [how-to] +:frontmatter-tags-user-goals: [configure] + + +The {gemini} connector uses https://github.com/axios/axios[axios] to send a POST request to {gemini}. The connector uses the <> to send the request. + +[float] +[[define-gemini-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}*. For example: + +[role="screenshot"] +image::management/connectors/images/gemini-connector.png[{gemini} connector] +// NOTE: This is an autogenerated screenshot. Do not edit it directly. + +[float] +[[gemini-connector-configuration]] +==== Connector configuration + +{gemini} connectors have the following configuration properties: + +Name:: The name of the connector. +API URL:: The {gemini} request URL. +PROJECT ID:: The project which has Vertex AI endpoint enabled. +Region:: The GCP region where the Vertex AI endpoint enabled. +Default model:: The GAI model for {gemini} to use. Current support is for the Google Gemini models, defaulting to gemini-1.5-pro-preview-0409. The model can be set on a per request basis by including a "model" parameter alongside the request body. +Credentials JSON:: The GCP service account JSON file for authentication. + +[float] +[[gemini-action-configuration]] +=== Test connectors + +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: + +[role="screenshot"] +image::management/connectors/images/gemini-params.png[{gemini} params test] +// NOTE: This is an autogenerated screenshot. Do not edit it directly. + +The {gemini} actions have the following configuration properties. + +Body:: A stringified JSON payload sent to the {gemini} Invoke Model API URL. For example: ++ +[source,text] +-- + +{ + body: JSON.stringify({ + contents: [{ + role: user, + parts: [{ text: 'Write the first line of a story about a magic backpack.' }] + }], + generation_config: { + temperature: 0, + maxOutputTokens: 8192 + } + }) +} +-- +Model:: An optional string that will overwrite the connector's default model. For + +[float] +[[gemini-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. diff --git a/docs/management/connectors/images/gemini-connector.png b/docs/management/connectors/images/gemini-connector.png new file mode 100644 index 0000000000000000000000000000000000000000..fdb3bb8144d6f30f26dd8b654459e2d97879c89b GIT binary patch literal 265115 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

2I=l@SoET~ANTp4-#zDh_uls(27@tJ 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±F0rP- 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%0DER}*(0lF4JbqX%GJ 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ⅇiL%V*+{)CS`Q2D&Vw<_!Ia)E!qNahk*Q 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 XlA4}5c;)pa;*W}=hC+q>+mHVbjGkVp literal 0 HcmV?d00001 diff --git a/docs/management/connectors/images/gemini-params.png b/docs/management/connectors/images/gemini-params.png new file mode 100644 index 0000000000000000000000000000000000000000..b08456f5bf3f03053e02f8c7d6b5027c84beb08c GIT binary patch literal 196522 zcmagF1z1$!w>L_62?#2n1Ck;j-8poZ(xB2gNOuYhpma!wq!Q9OG}7JO9Yc5A?fIYY zeCN4Wx$`_Td(Yl)?e(twt+j)d6{T>oo?#&%AmGYKi>o3apg|E3Q0pglU}YIF7^G|mF)_C?MnI4bj@3ZdRO=#1)rpD_G0Tv{gke%~`os`uZ&EZ%N+W$H zG!#=ViI+f~V1D%;tRX?n4{~bj&z$_lLP8wlSn^(DKFg=*y8C?ndcEKKp7%J7eWQQY z9Ub9oG(nDxruW`V+5!!qu@MN-KhY|+F!@}75L_N>P&1?W(62Djk%kyOd6)h&5K*jNIk4<; zwQL~!W0&GtS_WU#PuK{rEXc!n$Pi8$BXUVUm1P9Fy=Y?=OBKQJL8JJ1@8=gR0A&YN z`g2i1jjz7+zHlhL&q?6T>RK|w|In_xDnX+OdbDPrbCC? zBw2$UA*F2@n6lTyNL`B_B?`PqPG1P&EWI*V8ms7*OLnV=tu^m8F2qcZ((w$~_$+Lh z1-xvbANMu64ZbDkjb4IY;m9g~X=lj1;mH=XX&%6jJ|rQilM5k?H9U+Fs|G#3a*4}( z!z}ZNPCvOP7^>Fh&w{MtgX)J!A^o8bg-Dc{p!}5Uq=jEXiGC4*wG+)_G0O-|Dy!T5 z^Fbm;NOKy&p|6pdZbW@NehBE^5&Bj)MI^4iN?M2tUm&0wLEO*7g(Wte5YJT(Q3>?& zBFGu9K=%nmsG#)DdjP+5;VG?AX3Q6d!Iyf5gHcb!aA*UGz`zA@f0bej!go`Pd*I&WA>t8qt9n*42r^YCIn3C?2h zEbR~C6XE-$3W9o6e>3%9-O}wf_ALhGW|Y6Ii%=;Q;*GF6KbCexcMPX|tX1UQ8%{Oe zo8eIw=;n1ca7B47Fe!Ow70lFz_kQD-+9c{O{W!wrBxb=Q%l5FYgTZY#Dg!i+fE$KVXO8y@#0rnGOYO0?y;?2^!jHa%4t}ZgzNs9^=FI3#S0> z@%xvPNKQU;?}g0}q?#FQNpz7kns9ANi&B{nkWPG^7uo$l)Sp8J3BYYQC6eTiG(P)Y zyrh&Sj`GQ(d@9XFC7#vkVDwxyut4NhM4vQnDL(I)WHDyYUZ?dc<*Ic^61^b0mZ6TK?225K3ZeNV9gsyh%s0$Dj5+*Pm2}HLSJfc8|3$?ymQP{tQfpvsAZXr z@r;?W!|Vd>!jB~1z8w=A)8W*Ao6e`>Sh%e}cKieXt?&=?pS*b`qrZR1jK$?yYw+hg z>FnXg%2s5csgC3ajM9ug+cw`u-bQy!tS#fyNy!zGgQ>#wZ+~3L;g$wgps5+wOO{C1 z{6_rR^9+_~q(G(+M=NEYW0Jl8p%1Umiz#tjx=^zasjyv}zk=D!(K5Q+x*S~YI(=MG zWtKMXCEscm$3gN{E=g)emLI$`Ou0R|{maqLvD?9Er+n*V%VMW?CudV}sBly;XC^;r zYihIP^yoBhdvBsH|6FE4JS~4P>AC)UeQ90wxNqHh zJ&nnVDT--bd$*(-B2!|dX`)qBYE`*g##R)O8khJ7?nVfu5dHzA*FmQIOvDE0$h{|I1 ze2FK|hw5|NrGxDy3PlS=`CO`8?cAV#w|%2$ z@T<6$%7+F%di$>8NSY8mWTkJ96!t84izU z&f3Qg$6NL}!pY6aC9bq=?Di(duY0tPO&$C2l3<2-#)|XF3mdh)daUPr^`ou|#|rBM zsrMK0zYHwoM&;UQD6l<9t#qL*#ILP%Rx8csG9lUZ!=c8^#%sm~B=)2RH;${tmfjSa zQ59L%`5VKyJW$QJ zSy->|{dDXZ_ss9iuU2`gUX$BhZJ{!DeOiC2!Hr^*H)B>>VzrX1;HOZ<6=YphT$#_j zAU3O7zP2?UQ@G(}c=N8T&rD~kvUnz7hToZb*DU|=NB)#~y}db;He=!56sOZf>|Apl z*-r8{7kp?&t&(&%cHgss#c-kTHu5?N{|(+KMY)isBh)Fc{CR$w_QFKO$l%ns@kuY9 zWn24b$VkS^eyPeAoWk0!^5>JoD={m_;rPk)LPOrF4yEVnXZam{M2Ya!=bl$?avpLs z37za41A(c6o?)*0ZLW>SQY;s`JRXssN|vHFvajBSkAoZCZ@lvQ$_npFC)R#5&TAx2 zOI5sRd}ez(TCr$pT3l9aQ2WUK`>n}QpALl~KOf}K#&My)@pfBrC}qIebm8SJBdpl9 z@y7Sie_MF>esW}M%60d{LF>3waQME^x{%kQ_|dA|#7*vK?%F_a>X<{F(~CXKy_zGB z-s2+DOwu%Wxx3M;vhD1-9)EAtyRm8R+Txwqi?ODib_mXbmG{nFWsPvreRG|kbJ{|@ z*PEMPD=$}8YLxQRQaw{|0#1zgG_H#k7N{EM$mpLuA^6lrep!rw#+Vq3+O)HWpge+* z-hBMj_{;JQ9Sd~1_m$M5@Q3!ND*6J5dH(nCL)Za42iXUvvvi2PZTSTi6ow@d#Vs;7 z8@RowrQlT*^O#Bi-74fhQ7Z!TPC+G^*Bg4hLDH!{*F3P-h(Jl{p@|+1eG5bsA;y|A zCJG7&uYhw51Qf()2&ljrBJdSLB>SIpNkn=Ct)V_rphsqk|w7)t`y}=kuR+8oQYP-cA0Tvp*lCdEkfsKS$skvGADiGut5of(U|)xTv}d;_e)J@~Ajj$00iZ zE0RPIg=j63sujKFqsQ2KsE;2j|4_#+{-_~do0m7a6%uk1rfLP%q^Ej|BB6r#cxH}& zV3#(2*W`S^dS>P9LZX^Fx{LbKqf63ES(Bgt%gTNAn zKm-BtUq8OoB%Kr4QjjG4gwLHfr214Xl(@kdP;&Bd43G~3(m#Gg?65y0XDV|LPen`n zQ@Rn*oMW%=KYC~yXtCDgX-tHi!A)%{jtu z!-on`J`#jR-5VdHJh*-=6f|)@kU~-@vp)2k?I>br8DfZ$ z6d#$%3C&r-y=#%&{e}-r)g;OiK|)~8XXJ*R9U!iVPsRBWTH}8gjr31e25ziAMI<6P zEy-6lQ?F4L$$|w9yAf=a5fZE=aQFNF|4ddqlR^t(3l#>*9`=E=I-Y)1e60BpNBgdl zVqidTz&!zOM8N{=AEl3knUwx5Xn&RsLJ{}CcyLUA`6f~ViGIP=lpyGHar7xV{|;~%CyAQ$JuRQd5#U-6#ZQZKnl+8Go28uLMM^vxpug{VT0Km1-gjgFXrcZQ)> zR3zqvB@z7r(f`A_)rgUMqQrP#QYlzRd4nF54IdFg>^4lOm|#e+68|VUq6%T7u?@vT zf_nf6yPK&QUgqGS9Uojd#59k0uIf=F0fFo2r1-zd0O%G?5IMnASCG{kagmrdNVLv_ z^2Y`OI4j|cv>}zZNDNmmxgeA+UFPw>^y;4lgD_F3kTM57z$WUvWm(ocAbS*XnFFpG zi3d9&BhiAkDV`hjONwRi29QpMLv5micI z+WVvr&4fWB4TuNphsaBKO=PQ|PCD^JtwlijC>YSFZO2b#59*?E)Fa2ep_wpdQjRuV zfQ$R@a?n-Av&|778oZMR=@YOc0^%s*HLD7r$R3=53-bagb99t=#wsMiS=wQpvWyDU zO>3Sg`Vddq1&gSQtl|d9OA=#2<(KT0@Ox;gdaWPaI}9TUA0K)~x8%@=v=nuQ4;^Tj za_y$Id&r+2bAi6<%R|kxUcN`BO8G?3u|a^S!lzFz`OvDP^Z_fYs;0Kv`WaB?L;c{y zr>y8Ig!Rj(WL`vFbgCJ%hcdQRvs4eLY;rTe!n>W|8H=KbqhIOmo}W%YI1nRcps!;1 zZ5n45#UJ1;9v2igVuI{%2WBTDt@zJlsojSYjw@vYjyi}4Xr|m(oc`@v@F*i~p@~1k z%TD~XfdR!EWt6?IeMXSI-a{9!r_6TSJ^FxV^7YpT*@$E{M;s^l(4Tv~Gx_Ety#cD- z^;4}mr>$XsV8NZ7NJ~ES#3);OyuJ}#fnqa+e3BwDmh)PpU%z-9G9Jer$xP_{kfiwj z5YY*s#2`=zu}sVD{y8%{xHlNb`=Wrl-reTu11xN(4SEBTEtv}fbixRWp?C2FtPxEd zVEyYKswK0Zu4iyIDF1CvnnbAx9us6|eWP6K^*)R57tOj)-~_B{zf#-P*E-{BJXTXT z0!K@OuRiq74Yd1M|6GW#F3ln~wEh_H5y9GzbK+wYlir0_?Caj9?gX3-=~=q-c}Bgp zL9zy5w_)Kiw8G+Lv|5l|U8G0nx_s7hx}S3K${{dM`f7Z{+?sIX)m5l1yB2T zZpmaJ4&@tTQ@0x0hCiSMZ4pqG(Zu@{tc2oTy7x$PV9NZ$?E$&6QR0^mE+$RbYi zZ3&i42Nd3atD~l7MiG&iEO-Rq<1G`ux^t7cGMeRjV9Tks zK~8`Jx&Cr^v-u_yT_w{1ygofK4`#Q5XV|_mQVidf8NL4fN;UYyIvcv2^}nf$M~H}& zN$oMjzHTW}-Zx@T&j;eG*!?t|tCvmf!S|r#5i$YKV77!(zOXlMoRP8C0`A?4u&YE@ zalxYk5Yex(*>(v?nAOOM5AmN73E=(hHrYjW6WG@r!TLF1K{*5W%x?%vj~^urc49&S zR&KD~l89k6pym$vr+#lj1XKr~&&9R<*8XjL4PpclMuK^!)%#Txuwu>rIeTmGP^g)A z7BBk01-PCO5MWjLVoD;;&+C;L=qg3-JM0@Cr^#=2C25#xS zBbyCX985*>?`RcKh~Ud)i6CUmUOvDuMa&(E_+g(@&Hv@#dv-!kDZ3K$mBhBbX>mJ*n^)c|PZn2rs>?z|5+ zld(qSM^$wmAy|aJ`B{8PUt;Na-`X=oouS=B{8gLZKdIT&Obw`wp7}F&KKNkZg4F>L zZ%i^7js%KW2Cy^F5|Eb+uQXM_y$Oc%sp8ZAoAd8-SJ@D4{w=tOD1=M|i_jhp zMbJrrsS9^-gIbzZl|ic~^mY^LvnJ07Q{HmWy-2d8kzU+LbMC5j+@a>=eEaI{59$D{ z$MS=*X8(+IKw5y@;~gZGEk!)lW@g(g@m1nkJwy}9aLafuX^t3K26_IQ2q(aeFyW-* z_5PsUJOKmw8{Q61Y70eaBUsdF$HAlTtHHkh9#sofN=jSvg`ve?{%O2@{dIhNHW3=` zYo_h#$?=R$=xg#)C9iOn^u_0Wq+6-=mIJ}5A~HMN{AGC@+>OWEM^mPZ##^OpQ+F=8 zV|kRg&yu4H_Zs+51*d9H>zcS&%tiq?Fn^c-Y+VN;SG6zbY24rci_$;K_1H2+@81{@ zdJO{N5aJa=Zwic;9IrjquoEySANPl*#vNs=H^OmaTdpgsBC4DtxG#oGdzF2Nf81!M-cKU;0jmD+RjV`j{M)FCL zfPbn<^fVD5q|Rg~NZ|0}g%Vz>d^2sysL9!gz@x}bP;^)%+CE+RESBLz?-Y?G7~&xq zbh7>(DZ^HY%3gYAY^9cmG8*#!C>1NJ&2d$)A&Fto(~e`- zdgAg$3?)jzXTYr##`@QA88iea$6yk?s^X==(18Lh9GA>>Vp$dfHfxK{?}8ClJgaz2 zrdX%CupBbtY*Gw!&yD(n>4N$V?qUs1?eQKmSTL}da^szMH5XB|rOt5p6{c;xVYr~A zNuP^ScO277952~n0|$$4b%e*=REOf*aSZATgtXHvFV9(lzgQ>{BoqNel^X>w=d7FqMF?-u`@OqEaCJ39B;eMp@r>KJa$91<=_X#<~C#&5i;ko@;N`-yc6yyU^W*jZO>=_LUy7-k%!?jJ40H@10 zkE5;Jv$tcsD>yaB{Y9#^>iJC?9r5eFuZh=15ruYK53-M>|HgA#gwos~J3jzy>E(xL z-~W95<`~zyb2GwjNraXO6oT=&mub?6J~NfJlmPt9{c(7D+|o1vHz>1>WtH#@tt3QZ%`2K zQ|i7X12UJ_>;WF;sZW`E#S7te&GCvnnHe=?rZ+<(sIowhJ-V7ct+cnXt-@WO#u>0=Ke- zR>3kECQ+@G`1+h2=z4KD<6(DTR>)DO30GS#_`g6<~0r^r^%D<|{;416(#G`P9O! zY>TtpcAR$VVh>VD8cuX#)1>83J#I*xu*!zU<+Cc4Ig5kub8O z&*7FO6>4~YU4S2eDR=nmm4n3sht#duik5>lY@D7PuyodtEGzvzH+bWwyh6NDVw5UoaQdX9mYG zs7*iDxm%LTG>F?dnya)vnzn>Y?xnwQUKpFum_4{bQ-!&48fd+99xu?NgE!v$T3z3{ zUwX})m-gKV{q9Xtuh(Sd-O7s2QcRg1UYxb3_P)Eh_RNooA=YZR0bg3JZB%-C?x%TQ zX<;Sk8`8+dL=e&_#%XgZ#j_6-umq9YNe31Y4b)9lXviHdw_EXh-``ewZlrmh)mTl} zYdPIjkJN{*dB`sd0~Sb4z=s zy=uO3h8SwL_Sg^Ad{v2jo!l^Y1I63k0$^bL1a{}t&D*@CxIUd-+pPB9x>s*Yv(yV* zLUi4_+U;%*J4|z?@@lUd;+XZA(~7m%+zn8%NjTDiGwqJL+SlsQaI>8D5TzqPXX95Rrt(-^vH{uhItJhgyCD; z8lnRp(a18mPSRB^kK=BKs6Qo>Gcpw&{ZV`s8!T9xPDR=w9f|6;<$6s+Kl($fRJRiC zH)w?!OU_2>Q}afI0V@%XMc*KaG#0b1;hJck4+D#ot-AseqNl@*WGAaDXV}{(+u6># z8(c|O^Bk_1YZI%j;X;bVwSx1Nd#A(2N=m$kZA9$q28`zEhrcI3o$)1AS;?H&vt`Tm zC~#NA?i5?T>>#&yn7ulzUr1n^3gm()xJo^DIasQO>-uLsY7OetqD>B|Fw1kO zJ9q7#oR|Tg(4AASb%s+tW>lB1Dys5pC@wMV=#gV-eD&1TfbX?YZdg^9bya12D;|IE zOw63(s;S<_wJOoAhjCk$7p(TI%yI2;e6Hofrk|Yg9QT5_U^t1#*_PeZX-}~ocqYl{ z`iw%w(L~W(!(ue=`CG+*ZRICqs#`)0Z%b0bbx=qa_8#PNom5MJofvSBuEo!Yu}~RB zMOBOzR~DSz2m+9vTF*RHWu_sY=b?bSFdx0?mIo34cp;?J_#Q8< zm{MhD8r472PG!p%1A2G0!?HD2mnQFeJ%=MhZs|54|KvVU;B<6QzE6~x%1lMby(h0FXi z0&{q5$MY9Yj&C}V_3CDsolkd&w5-lYu%U`SRlwQ?6I=(g=`Dd9X>{My$YO0UayGUF zG^-YdIKhz)<|xG~=P8zG#^QS2 zRJWtx>NCJXP@o;J>+rSVP+&rlg!PH3{sIx9U=R?XrW<8R`)8b+S`kyIDk8_-V)+P& zhU3P!P=<3Olr~2MzR~7hGF95aF#iB`Zp@9~quPZpECHipGOF@%_zyv(`pznw(SzIN=_ zc5)(F;Oz>V5t~LaGI(pl+4hr~bQLfp65^ilRB@knB{edYqJc<||CuE0s{6@M>I+dh z0k{wh9z%zYi^<1iGd0PrA9*}rN${3VUu1NtQpaew`Y^$3e1EQ1+F;}*z8`l$1cv<-_-C?=*l|!K#6O38e^t7>YQHFxToQW}wiw29-(xzs&R}r<2Dl90?0T zrXDH6b!$PCS6=)MgnYr7?$o^YPt7$~P}t{{J8%O|c5;lB;KNc68ysow%H;kx#veb7(AccH%Ohk^Su> z9W+&U7no#Jk^rISkCVV&mkz+n73a(bU!;tre~4>A%T>XpSRY6+-Z=c!o$Ofe)0rPV zRe|Pzyxtq}GK{Ci*#fwv!5Yo~;&m#^T6Zk2fSkJsr{z4~fu;$zA*#W2|9~(&3Y)o> z!zBD$uddwfdVeaj)N|J?L8dwY%3sKL?b%_omt);YomkX$T{(?M-cSx9C1|&L;{il# zf|Ow||H6VifV~eBPd*)YZ0sD~A~WjYuCs!EbiX!>Fzi1>6M8y7FzBi{)9;vkTb{8# zj6^Y#&W$l_I^;<<`>n!x!73M3I>+zQcqid&)0N5|S~A>vLCqkv;+88njh-{)1r2A& zT9pL)kyO2pG+eH+vwv5$NLPzN?}z%RIbYX})<$wXlcA=Ipn2gTtrA8x_8)C?NwUCjG`; z9H`gz9yf3ClEl-iUZaz;(?S1px$7jz7dHo_OnO4BzX4E$Ab{79-@0QlrBpUQAG6lu zFbjT)kw8uT1Bjdq#1Ov{z1q^=AUuNe?*(?xr89WI(w#=|Kevd6S-0N2Y5vMQw4^Lv zqoZWWpAlKbIBCBV^+tuZ%iTkZ4ZgvcK&0dnM%0v{7nFx!z2bIwrQ^bMSMCvMW?qw_|hmq*V8(* z$#OG(mQllFl|PQ<=JMdN$$P0Fx1Z|SlCz0?M!LoNf>}Q>Daxz_;00etCn*t+mD+pke!+@xqsU@K~?ZKpcwaQ}vKW`K{qn zhb}RLgnb+`AyqV?E&PT0*y+TbS$AgxhW9O$dMC#m=0{0Kjn~hiPl>nKw{BfYPtE2t zzgE#()E!f#^a@D!i30$gZMGM_(21G4V6I5omjC%iouGZ`PFYc$e{cQ!5|Z0vHj7nT zz*1E1HJ2N9;JKdFkc!{;2Uiv792<{%h(E=JmQSoaU3VVJlvtfG@Q%hM>s?p>V0HfFGQ@Mpq22?~GWuWDHiP|X#qyxwplrJ(}V-Z!{Q zZ1@K2I`C8kgpx>+)Lmb-pU*j;vKC9K49A_%Coxk%;8E`ge#MUYbegLoXZ|cQ-`~9& zzX~`9Jl0*tnT3?9g@jirbq?XKZb{=zYlj`rBLPQZRKv7qywL8DM&V;1-n758doxcc znk?iC1$q(9Nx{kcRO|MfGd!1G7bS)_oGO`Pb{m1z%oY@b-NGiATt z-M7bo(Ou7Pn&OxvpUN|?W8^+*rj+CoiWi>e>+3vKZeFJAHuaeGwtW9LWa1*Qe54WH z&s!B~HDB636H_-g^V!AuY;%3zoqO3c74T1(`EC-Nx11+nM^|Jk^%4zx%}Tf&h!!Us z?6C94PsuI5AMP{32Hf0e-R^Xv={gy5W6tLqQ_lxm!@KOi8yv*CJ4*@*$`@IJ$o`|cVO$lv(sF(uNg-4C+zbLff8eV5YtbA*&|20ns%>1!%KNT-kp1E!C~He zxFs%2vw60i`6K_q6vR!rEmEuyRsK8bR2j%Xy)r(}eZf+-la4hYz_0z>YxOW4oJlz& zm_rxJe0{bTJz_cb^=aUr(1C5eeFJG`sO7B6;R`QE%KXZY*tBZ<8ME6Hq)cZ7AwBwQy?%eJ)b*Y>@33q3gOO;uA->?Yl0U_XL|r>Jh{%-&oInI zA_s1&#(Eiy&K0~KVX^g2TTO<6bBexlwp=$fN%qJ~a5rJXEj{TLOO{l4q)VC=FTTaW zmGED>dk#1{7!;dM4$%sI&Zm}?#@f>On5Wy*?ig0$j0Tea!D1q>h!PNJ85WB zg3CEl4DZ+OK)$%9MG86q!MrHUxE^;Ph2OxYp4UxNEVqCC>yA8z{kO6t8~n^MgTk1V zF#i5R_?$FL!RWl~v}KppGOFF})mfB{9zXwE%+=3R5GpaYV?!NW+J*+&Z5Y=j{+A17DlQodO7dEln!6mvyZ+Lnav98^oh9A7 z;+C!mD>DWH9bd;N2GI27h>~jAJ6O}kU`yvBjY+!$-lnctl_OLTXC_Wzp)(`sD(KfS z*Cl`*$Rya6_!p2GxV(F2;1=vI3pg^Z!5_eBb~}T;)3AX;&UM`y&TK=f+G@j6k4Mw#vK)U7CTnPU8XWFZZfd?m z%Dmq9R@Ns!wo@*v%vCkQPwx!b3ivS1U#Ohnw{L!kl<5L%pGBMeYqlJOjN}XCo01|D zGjFYWy{A)t-*orb6QJ@krI26+bG$CaTWV@U<6Kg1KOr}rN*yBHg zc`ASv0Os<=JRL1L|EM_XRL(P-3ZeM1pAW%0sdqX3J}pxhNJO6yRnDd0>1@F5z)eMJ z=adE-SH~Iah`E+6&U$_4T5NZ=Jpyj$0AbFcKNfSfOCEzLLMkH6GDl5E9IG zuNu73o;qw`v)9qWgf1tb^eH`dHQ0i|Yszv%@fJ2-1GLo8cN1l<-9*ZL_4mTpGXSHf zM|PO5GYh@EZT|9=i=ay#WE2%eOxA{i%S4Lh$nkpk7p?VXjjfMSf5nH$8Yw#EBQ)WR zh>p=A(*rb)944~6&jS;!ZVhS+bNKYm)6Oj~-NRDT&o>M9j$O{acaKC-QgkbA5L>7n zi!Vfca_jch{0~r93ezfGX-M_<`ho+X2u(R5q%5>)9_1VWU4H4Dr#d}hf+Uos0BYnK z&JsC3QQ>GKXhFf7tgRk^Ln6Ry2F0P^qWV>d<_&@IQUZMrwk>r!J6?EiGuc(acZU?* z&bOELJFua(4*S&33y%}Yx&Ycn>c5Xj@X1@>%IzvYpFb;q4ogS?id?3Lp0fmN+L(Js z3tTjLR&MRO7$nqm0NUVC{)9av?W;?V@cqq8;~tF=E#sTXi7Zin``HzMxapU%vqV#W zXH+5}(nx3;{sC8-h>$iqlrQ623bL8u4eaH!7AEdAlV3*R?`I`LbM0wu4%K1lZ_w}A zf*B%{D?rM7aUt@p`%atl9@p!?=D0T|kCTr**AD&C4lXObHfuAS>er^L6NEc^X&gZA zSW`(D7m;d+LqCgQl+FvsjXwMsxI-0Ar=-3e^#Oa3E&4yv1WC;dz>`cmcNrXzq2I9c z&aW=V8{*?%0dzeg5KmN2QjA!zxFmsl8=Ku*eQTQNPAb7aq^PlZ)FbEkYa} zg8VmpdWs%^WKnx1*txqhwUVsxDIo~NQ>~q(#O;_q<++hWXOoKz0mjs8`a%lp%39n&J1GbyEUl9!7qHk6qA))r!MK!o5 zfdVL%R@_|04XYRQ6Z@c&C&*NFeFYxiY;p=n)KE)75D|Y0R|p-`NXeX zKK8B%-`C42{?wvdKkUqa9a)H+bbeRr%ri~Jb{L!&p2h}H1J`2`>AEDF;HlC0pF*)j zN?&dpylxJqv|uLIixz`# zbfs9AvGY!tx3OH&@4d8yLs!0!+3gi%?M9L`i22!pn!5^)$MTTR%M8GxF_udLRT*xL zhi>Z}95C5=ms{gPlIk{Wujz6d2LDu#+0-hhIc~e=fOxdZi~!_)I7`*sGk%c}Zb(e( zi>VO?fDKt1j}m8R?!7!$^RkUY*V&8?n(~fr8KmK!bM8vQH7jS68Qq5A_%V@6=s{f5 z-=*BoT>dzn#f?JmuIAR+qe8ig!ew#6W2)Ww53Cy zqDm@q92Y(VlJcJ9lJ{S7^02gjZ6WNjH+Z?UqCG(T*$pe9V(#ng#DK58pu1nO*VpLq zxOWxU(=~x7Cq`O-SW-qNQrmPiK2088r`dC49Gb1(6{QkXaXv`%wKxKZTqP;&vFxZo z!2|D`p%l|LfUj)ea8{*KcR+$kz6=pa2A*f4hBb71wH!Ln)r!%RqKc!4!y?5>- zIJP`vS&Z^a8Kjje8dfbDH8pNHPq|hv8b!8Buf-!Ei~U&)G5R?cj#p;Ob9+`;s(FWC z2l40r(>VT)k?kt3=7>AR-!%FnS(Ht65T*Izj#tWyJjbSM$_q93b#TO|$HR;bY;Z*& zA7s>0J+T&})?L@$czc#K>vCLpbl8zrYb;7O^_ZYg_p(OUYmHMh{+BTvb{#kRYxQ?KsR8|fAiHXqz>)O%;DYx(Q;H4z6(5df!CH}*XO?CBjAsyFxU%qF*WUIS zwTCFfRTjWW6uA2O9!pw(T;o+rtxBsJ4v4FsdX3tftEt?zqaGG}C*uofZr`?sEEM|72%I zuGaB%fdB0Fd?wp9l#A70O7MQKidJT>*3>153Up-t_noBoZSpaL&kM3SufLut%hJ76 z%c@OaT)Q-tq~3mhJlc5S-T5n{q_G!Y zfLHedAh%2_HgoU{qwLR0vmtqlF#$aeayQ5{4jE6Ig$CF^Tv&HG$J_P7f4K(;t;hvTcehvm_o}aZ17lpj0t;tFE$=Ivt)%ING-Sle&)_+w&T{9-h~q4yB*Z+|V04ksYe>a@w1wfz-1K*(}_%_J-zQJ*>e@Dn!$J9kK|sm``&yT`cCM8?bYq6jzeiA)e(YmgzVctf%ggfB$wE>whL0Mh+*RqpH| zI8?u3x>i=?oeF8l2KUx{uAk`IJS)#v%gVtNe@TjzDgEf|Z#V-XB>@0WlZ*Eg*t-qA z3=>*&|h8d+*8oEw}A=&9ODQ@ zTH6Xa$JWzyLC;ceMBi-T#-VtPX@Cx2PfPYk(mdGpLsyrNG>i+vB}mM4Qa z)-*V${?;aNUnQuG|9p1Rz9eg+Gd(x3J0hcXr*-oCPWP7a z&`Des3vQ2}B{M?m@9fm^@e9-9k*Pcz;0-ghr24ZwCgGsM=%H-MuiI>{%RED=Qjwtz z#Uv)0e0#nzV-m<<+{}+mTDJx8n=LxtD$(y&tXng=xeoAgnuB*h4oi#vZ-uL!CV$lL z0KYd|bSaA+OO@gEJLjaYx1>)lmo-XlR&2PdO9Y|v_KFcJDQTUUA+z(~%2a)RChF3T zmW`dtbIpT6`*m&Yp_|gBh@w4n#X(}58TGt(%Vy^J;O@0ZTj>|FILr#PV!98 zt1yRZl1voSwv*y%OIaxt3oNTr*}R)uI>ArpCo)bY!=4b9b*Ss(Ly5PemELtSRXO$! zn!Y3{z}wOGgZ`<{%fzNp>GJD=BUf-_di+Z0Dt3*!A>{}*^6+HV5 zn8~11RgtrFajNt0dJUvZ5NG$_0OV2~kcmi4V$`d~`v#5iLamoN@+=rgnY-W9Y}^R@ zG=C|mworZrJcydlWW))!BFI!#9m*HqaDf=drZ^4i)4??G9<(}+U!gYl8H~@xl&#UN z)&nF?iIq2A4lm_@>>F5?XjtFQIhr)Ym%G0^-vHj)o6xVk0h>O&Jwp~v#-5QJBKq!UpyH!2;<-9nP3{1eAfcTW#)IPW-?h^hM72d zjC%t)maS=6Zf{am(~Lu4W!j6|FB~E@^GBnY1~gN&1Rn|6po1uylVu_31X5=(Si4gYX%m9NQ%^yOFQf*%HSl zs-;H3={X+8T8HD$*~ctK&nh-{H{Vzpc$N&4I`w|zm9v5EIpu~x3I!c-drJy@FEVQo4|M|F=#hF66(O8cNFJa+zFww>N zg17OXl-ABTd=>6}7e^E(tpBHq^G}_{GIL^ZoSLetQSMVGo1Jm%(w%rcyVXdkZW+21 z>TKCK`AI>Wg$A(G?j+@m^9|?^*xh)4rvoIsUrU6LM24*Q+}~W538BZGDNj{eC+%J= zp%3kB&2mqJrGp9>O;U@+g9#gyX^D)`-;M#`h8joP<%f>&Bma_K=T1r|<~%}LoMDl? zU#^g#Z>0sy{b@w->tU`?5{8e$q`B`3BGz_{CQS7d8b$`josOrbOXfVn@TzFrLsN*a zJRUQ~y~XSQ>&t_n8B`>otm5N75MstHcwI_#$FV?413iEuEX5ZV%E(k?gbBZB3(-}o z=^}|XQBZif5JGhJG5t{OAVN?LhTw=t^xyy zd!_mhU9DG%^SCD<*;$<=3$e`n(B5S6C6UgVX!=^Z2+Z)4ck+uXCumr>_@>yct%I&D zl!c}wdl^PM?&o_98E<}|3I-JrJ@6_h&l406M3s;PQ?ZdC1NngriR1MEKaB6TAy2za zyZ#^c-ZCu8u5BB>P!R+uDIX(dmb)+zdyczIvWG)TLI74E4MUl2`;TjR&Qt=# zhP0rTtHFLwsRY5H=>h;@fmswwTz|0tGQWHvNnkK7L{_ZkT-FZ*1JDT7E`EOtag0$l zg4&jqRQ?rg7xI#D;S^*= zMCZ_oh+qZ&EHQ(R(T374j}lx<%wa`6AhWUYY#`V&7b$xhn~lV{`Cu>v9$k0A8m;Yx2^CXC&XWZNrM#`- zgbNTiB{2&v>nPul+!AAqy#QJ(+4OL5lJ1P;^`E*C;0YZCwO-?cIEEx!h1JU;!&r@Q`IGTUn-^X=ck+f+yhyTY#qcXl;=i>A66 zJc2?!*;g~}(M8H1vGiw~$FjaMcD;U%J^oE+a&|n?rlRmKgNFguNlz9m4ZyY+0#NEWKe8H{zMNU)kXq}A00++l4E`1-Nps1VO*tcO;;gLl z?+)_oGz#GSug*I+G~b;aNv#hHfatmKSzZyPXIPF7`=dzyC_B5U9u};YE%*XFG;VF(19n!M_^;3AB7rUKeq^_*&p2!@H=SG`#&Y2f zy4RyqGNEiv@GN-LU$7sU3`%BZmG2{axZ&yf8D)T)#|tn7v*w+j&aI^iHFa=aKF9lA zxpWmkUlp-F9`kyO>|M?Vj6no08Gg^ZBwzk~O^5_wwbaTU)DjX7R7UNdtZXC9*&Co;W;A?TPix^av#|rTUWb&<6HAe@t-&*e+rn<+!TQ&Ig_rE(cR0 zKTNUv^0el>$|xr2`+v2VudjhGifLiS+@~s#0Mia$-v+=;h_pQg@LD7SMAy&TWo8Oh zz@a3m#U(%)_w&SSOpEIm-%k~@wWWKe{<}pmyMF@U<75eb!e;o#18)J95rKH}U=VpS zqulvtBLSGKU~(Hie8y zPmFcc$pH}mCE0&kiM+9u=(}Xt1~Olb@f988d8Gfp9UX&xV1KCiI)fa~ z%8ja?vnVBRU{ThAZx@c)LoQ|~U6S+t<$}5L?+3(c4lHS_`6}|e;ly!F1@wp) z$h;m2(VRIb`!gY6);!(j*CV@$S3_S$);qFAbzjtMx_gFu`sc68WCKhlN}jZf>rUh> zW>>;I{zz5*_aBcT0*(UnRdw$AzXv6mKVEkNtFTdsX!z%koMrSfjHgceB44cHzdsJ} zO#F9&85h8VI12~+pLP1m{CReA=N=eE>!}B{ttmWL4q=V}I3tNoO5aQ89Hb1hz=f@g z*@Jq@q$dG0W3kB&kaM5)j|=sBzzQLVTdpMM_#6tQQ?Hk8?QpK{MQa`~5v||;>27lF z_GSYoMaiamPDEf1lHt7poIxI6$i$O>^2xK#m68oO0}i9{vq(?>IXsUdVC}sA4<~P) zpgMT&uwo_SvZrB9W zEfXNlv>ayeqzbzveV`W^7idr9W(Vr-XUJ{0!6iS@{iU1%2TnYL`RCsP%l$Zwu|^x! zL3K&Y=Ec)?%RGj=JSj1=!XsK*bn{_-xjMH`=7-%2FduXh*O22r7mx7+MJ~NZKMk8T zh6x!1e=Cn!U+8+;5v#~>$EH0&_?w;4DU(O9NJrFQ=sv^^XfrUrTDoo_o-T&EciPc6 zZ0xNAdh__LJ04VacdQz#DGxCDFboI! z5q-M+rsxPhL_)KA%Ki!xAWE2eY{?_|y>~Q!p$w(sifN=b^0?8&sqt14TF|}0ZAfkV}p;5!seyu&ZyN~vi4oM zw+WMtjhnw!Jx+o`Em6M#4BK2~6Ir~s$P^29fyaH7l%8KHMFcrKCH+xEC4mbKJ~SDh zW+j($&#YMMkv>UCsa@TB^Mwt~SJ{N$jVv&WOOXDp&zb1iVNri@aOVij=AAH z*%oo@@$F>91U>(&PidYzW0(myr1DU){@Uks=_6Juc8w%}WjFSGn-{)KNyTt`MI8NX zststn3OkMXTRmyMiWxy5JMDhc0XXEHZz@T>i>S;XCAX#0>h6U1vlb9pGEvrvjp!hb z366{OEX>5#S!Z=b|9E`__>k~t2TQY>b16eWNaiyQ@-T*hOjW8@3gr zygh0rtK3Y!ijth#93a<6JmM>17n!^V-nQZ!&fMfje*k-YeF*?XK=w#(?yIbhlyLV* z;%lfmO-Bt8c0G&^Abn3Ge3u9U!_F8e=lTWlp`vqaZ>>6!-*ea*c%e%UcblShDxW>( zG%9|V25=m(u*c8%(k%jy^h3y)mIa@WNH%yqyrW03hbgJBZi~wU*rJ(j*A*G>=$Gil zmXtSq?~a(0oY`W}NbnClV$;oUoF%Ch>~$Q-Pb@3;&(E%-}T?g7?z39|PRn_WD%E$lFEW#fdjsko2p=c#c)sM6B)48*-ZD*XWg-Di`aO-?z*3&!6jn z^uQNR5v6Z4=vV?%>M{aR(li4_H@MsPNa;r#AQs-q_A=LBT9g?JLb&v~U@jmLvcbjg zVDh$x+q9>Yn!CQZd72zXyN`PUf}3sM5E$4#F1Fmv6>5`NvHt{^K1HElO`{~|mvWBo zG>M}%YBT8zes8thW(NS-wmt&%6#ket;$$Ik)KPU6wk2IB*Z%r}Xk+PCp3Z<@_bd;f zb5rHsXSp}}ZrlVKz`k#{1z<;G`fXIkdfW%N`5=dT*cK<29){GzZ??YfYh2UV&R0v{ zzXBAPwzbm9O4XZw$8Vhv_Q>}f@KT(9liIetpK|8E4@9Wqs@UZW@awA#PgId8PHw~$ z+jJ_{=MYoC5V(C^r)slL=kt#j{kxIz{?8M-&4e-VTFl7wNt+W^WOrOF?-hY4Oy#@i=pDw-$0_xHCsr7e&5=o}yogpq?@!V+h*ahN^vKI{6Hqio*{WG%puyXP#eI*V z0*~MC*+H7Iyk_8!%*$p_wUfz}OhvOdQqiALU>N;GM<|oOa}UY>i*8Z7wkrbGc~pg< z)g@n_sUc~uw4LF;O?;msWBZV-IS4JnJ#j!qafCoyEK97&8hs8h>{J~o(R<1WD@vjk zJuWO11EFMR4ced+csT&=5+%CwpdRW)TAyvcgx>bQcdK~h?mqfa0it?iqA_LC{dHiu zz~Zg5ah_E`rQLd0)b&tqd1{eY^S#pPkV_LS?r#$-p1!ff1@q4HZ+nXH^A-8p+c5q% zZ%Q5dF+-|@Mf1b>2w&=S2ETUrO`a7-lKuXA`3PHnhyGO8^iQO2x2R~VE)Dgl$q0Vy z)Eulfoc?4x$?u=kmG2YfvxU;l2AJdDumBze#K)~6Q}b+wr9NxD3t{!ydz)mZ2#sJH zm*oIhaIU+iKR`RyTs`(OHBKXZIgGHr2k2uLbK&*jug=XK~*evQQ}z!z1sW}{xN2EgY<9FBG^ zeWc+Z?%ZB!4;G5JN}vtWVK{3-(W*>vfhBq;{%uHW@AJD7Y?k0bd-p0N;3JQ@Z;N^F z;1XVp_wNM?JC81{H8_#7<~Is`BcsU+eoPQ+BHA6&U6$=xy5s?XPu8>?V?FOJKRlu| zh733ky05mZKHi?~PVfKKNYcL^Yfb-QH4`DM8eU647uj49^g#TY3hSr>Ho zh&)?k$XpRr9#CX)Qri2#W9!<%&NADG#faEux-U3xE~!U;@FM&3$3RSLbJK|3kOb{z zY&Ls~d^8s(AFoQg686%*Nh9Adoy>p9Y+K-IQGZdD_qy0LMT~LF!QxZ=-M9KY0}tu~ zjzCqQF1mxU0e(A9^Tv;UhclGZG4H!SH&%74$!urRE|lR(GFuxH#r>iy9%}{1leF%m z@vY^OfqPNuCS`?@E2h&ttH*0CRnHPn{B9d;L=p#EPt{FTfmYpI&88kLzss@Sxl7YA zy>MhPE-kodGAC4%fqKgekOh)#7Zd6x4*yez{Zk#CmYIK+B8*12y`2x=DQ8f|_89mr zkqIn_$9zi%7(R?bohg@PW?SHnp;7%AoawObFyfd-Nr)w(oQp9uA?mi9kSFarb$XBD zqQZMq!~~`c9WmpST8kld%ENNQaSQKS2UyKzwlUllZSW&BK0U|69r|ycJ7@F|X;){3T_aZ{bDI{HH+>rp0eF|kPW|Em z;?sz^oReYT^JsBt7MFj3#NE$fWFR|K5C_zs*H0wVT0E8@RzwRxcm`UB(u#Qumx=;O zVQ=L-RLg0uRU_yryBtSF&{yLikSklzjWVgsM8eQ3cNH04yt5Ay^!uUY>$v&ABApOx zH+J#|);4*sgRFXSY5MuTPqI(4h)=$rFoB-A89x<8*Pb(M8+1&?Bo8C$ zP=%Hhw_Xpu%|gfgA!F-sNB+o+vdQek`dc_^c0ME?CL z7CiE}-gC5kdS$xzvX;h-gU{{>0)fyLT^`A9@cekTaOqVVW@Ze<>H~Kmz1>U*le>H$ z@s@V9&o^|T^XgH=i-HDxhdIx|Y_xRlFfGns(qr4=D6r=6;wc{I0yxK>x%zkfyvI^j zs90C~*rH%0UBAmu_6|SKkJgGZgH<@3cGLV{lstiTi_sI@h{Y*Z-v4<7%3kA=oMVB- zM;Z=_ef|-G{R1@8X0bbS4q_4T5E+;#3C63;s`Aw}Yov>VcM{*n-xG&%v zp!dZuWKZtYyEE}#6=AuU9VzuDB=D3-h?oH0B^K}rfZ9_ zlDk;nV-8}D#>4rzDYud~yZdTP4H-c!SLIoOok8i;p9Rd#VL|p? zEBZRWMy(`k`JuFX6-PLdnIg1Y&+V5zaC{qg1!BW#av4rNNG}hD+oNgF{6LPx@4Tzz z7JJ|HfeDvE;jbhcMH%Wn!rGl@uL5JGFAb15@`ZhqJ(RoypfFed##wF%w2Y6!!BD@0 z^~+;bUM0>`4eAEvhZ2rUe3FJ>3Wtxs?vDW)iFG}}Sm(Acr@9DX%b1lbHHva{OXPOidW^}EYWJ-u{kMJ)@bMtu8UB5GRaPpb)mt_Pk&C5DOP zwT}A>40y%5M@_U`- z!Ei)XQQy*{LfgDL-NAU@orR4h zpd?M2BG6V*2~XgPzxinS=eE>#01E`5B|3)mV5c~tE?9@22dBM2WE~>BQv;Nj!5n?ddlbG3va>0WQiB0Wn15f zRP*#x>3;ot;sB8vWOWsxmH_M(3$%O#1i5aM$ zNMg6fUpo^^_PAV%ffj&iR5DTePrc%6C2|P*GNeypJwaWQ6)mNfAVT#o z2NHPG+W{Jj{QEN_{;o!)A53`5n1PVCLuv)QAgU1_XLQhBrvc?GMyX=|w`zTn7Bx+U5k(B+$fCue+FBnvW6Y_yVU% zomx2%la5(J+rovMQCPl@U)Ko&f8DGgiX}V9^ZY)C?Iffev?}^5GiIvNd)$QnNgM`{ zka^!`5R(qfd%3#MDFVtxZtJ;$9uT?R0fpyy1m|g#B2PPwQhmWR!f}Qc z0ewlEdDd-|h~J-r?3am1^3;<15ulN2_xSs!HKRP-f03GcH(CxP zF2nI8bV2|^4bkhuJ*@DJN;84G-2S(C>FdQe!4cNq-u%S06=W(9K1a0=sW$*H$#Vwq?6A}T>H5uu?E+h+k>`8=c ztcGo`(9#+6R7tK+eY&G`e7NVoZWi!!2qCJt{cGRLVhpr}c)24SMqBl0^W(ljkqWK+R&~L(T#Za6K@6bg%786b;2P7GN|z$zTxtfwwgbDSU;Wbx0fz4M4-`d+;2Ss>@F!VO z`+G~#SzE!SrfP?EE8z2VgMP$GwGY!TZEAmpmXp`Luy-g`8Li?VmfLa-H?BKeP=OQ& zF*EZqn_ZV{2xI=F7t0bxy?i^DD~sp?i@F%=9dvgyY|?Cp*Qd?Qqs<@h+q&M}-Mtau z{T2LW(xw!*EXKsx+qN!KZ2?Hr5|w(80?MRI_$!1hK>#TzaMV zebC1Eji>ky72lmPyH051ive4QseHIEkUulN8z|5iUc3N%wH4=g{8P@T=GA-sbkll| zc7&w(cGbs>gH~;;+CN$vLQ~cy?C={?5L-8BOaz3tP1h(R?!FPfYFCO-O-w_{+BjTM zie6M<169v0;);q1C1+}H?Flg|EDV1Ma$UcbvK6k|Dqtg0;C{BJ=G=bBMxX73v)@UKEwUgPvOO=!v12(?( z61!pLOHId{Dagn6fm{AKy@GB}VAsMyn5!6)%mps6y+hl3pX;!WH0=K3BOTn?n4C>O zaxV6R`>R)9gbDnd#_ByGT^WVyL)afX9kv7JIJWW>bW=^5Bv_-^pu%NbFt9k|VoxF; zH_aP9g@f-;^;1NA>I!EH1}O(1-5|DgML!&~7%eqxt>cJ5`tVBi(`TRFnUZ~8wW6iq zF{)An?L<{oIV<@uySfD=j$W2iH}@YXwhIPDO?Rg8&etwdPTYEwL*X<@__)zwE8?)hqg#Z?p%VSXV3LItH~irq z3C40LWx=K6h9WwLo1iZ<@R-eOMYz)0co4j+oryAjs;_f$@T-N1rei}AT(clm1J(7SU~G9&D=&|^w>PN;asZQ!c)@M1$1{(WjQYE5+DW8uVBpC8Jv_$k_@z@ryvC!pKW)V%S+-=n>qsR z3Mqe^t>1YeErsS5#dtu4tTPow(v+&q8r%&K!I-3no0ukgUwk`6=PKYF7sOpo%-Ne_ zdQBgjeD<#}yBek^-hH_7G((g0IsRY)7snz`4F6(RK~4(hHDHD= z?viAcMiUFW82bkd<;4xUTbi?$y#1FAlLwM-@n=xiskjZv{V+Q3_GFvGFMSvdtgUxR zxf#Bs5g%X&J5U#oToCuT=d9JzVo1*7#XB^x5^*&?n>4dvr%0X@Hav6WosDpZn%=+2 zqR$u~u_BrUqH`H*=$ce>2ISd&0ZLKXNbB>>0+3N>y2!L2Z!NH+MH%<_M%=7NRaLsM z*>9fMWg4mB-5Mw~ku>>O)@Dt+3oKq19Z40v0R>=_Da-einh|u4yuO$@P<@VF30L9t z)&)Z1)}@EqSekl%qF6^+QkzHHfp_O7M77}%z52fFar3HIS##a#9gQZW+#~tx;Bh}$ z@h+PkgF!!YU1Y|o5NVAen{on-jv_eNsp%PTR{sw$EWqK zx;sl)(w~De@BNakC&4|+$7{=_#g|V!HJL&*NcHVth4tZj(f7{QGM3Y5 zn($7R4$LYw2js-^Q(6>o_M8QzXzGD%L~pvVfBy3&y*f1qhiOFFkSR<4PUQE?9e0-0 zaKndH8e%WkEXN0>McnrFFGSoFg48+>4Lj}@EpqE8*r)~yqD9K6`Lx@){#ZVKOtbeT z&|<(9ySO}HH&<|j8+T_!ucydPB`Kj;pG&n!C$C1!&Z$P!%=seAQ18rLMVqfdj}1Hl zc|Tcy>6M%b#6b23eVIYT6pY_*v|wN8k&{)!FOqNHF!jR+ZQdJ&nE4Ln5#HNuy3LW8 z;fZ0{7wKZYYW=zI_dTB0=5?2Zh`rBD1 z_emFIML1Ge;uo~quC>Fq7#{(|XR@RKR&B`!CoK;$jl;Z;)7#7x8Tq@n>^xl{qw+N?KOklGCAVp83n zySfv~TLT=-#v;Gj+HeUtblE!GO>`f6zxN5t#LO=}cxx6ayuBn5Yl1s`SbLprM{fA` zl~~bL&5kxzsQS+Z%^TN-?x*XbDhvlFv8|0*WFpnLsl1~`ZaRBuXpR%c&wOuf%A;;* z>`dU_*D}BhX?TPL2X_F)-+Z`miz0s+^l{YM7@JAmA6xinI{wzS{JEX=iE#-@!?|YM zYMeF+tH*phn^CpY{MwAUA-XR|F^)@rdyjvCZ};&&j>+B&E?(y{40<*Pc2Ly+FRB96}R<@oD8?;+v5})2bVYiXVfhbfT>N$;TsTiMU7yoh5iMe}U%m zHcz3sjN?X@6O>8Wz-8mp;aGooAf|O@Da~PSX4bvlZ}#;&N6FMGI~AVtw29=MqO*8} zK|!%V2#zJTAtM~D1a~AIvD)=y#OoGlu1bDz26GjCo%@jAHUIVXTLYJLaV$i0+rF~F zLHNJBbpK!E#U?-C>-fOT?`J%AHm3M0;9E&UdHI@|8YzOVtTrl;IHbnqws!rJ`SIFS z121#`y!UE*plp5Gvj?hwwK6D9fTP}W%V6yu1w2glg4PRfZG!%lL}_K9nUW^?4)os> zjQ=6__3I9>9`bMZaJEB!kEg)fNkdM<&96$lRtDp?W))O-oX0FnRSD0i)c(P_Y&HV> zv-lx?n|6>v7K^apP>f`3KvaWya`gc@B z%*Rt)%fJ8z=%>u=W! zJh4?j5!>%e_{*k$T|Qk4#nmuVZ1!0NJSc&9ZjOM)} zUB^Hj*7%o2M{Ie>y7=>O%M@Wm1V|00?a1DSYw|c|ouknEb+~OMLOFqg=B9bpa@|P; z)4h?6ckNxU=y}9V;-5CkCBgDW{RIg@*Em_Nj8DD@{``DSJO~PsB|t_^ft~^)40bd; z6#O`b@ZJR$9fE#nb-t)GF!Bv?kbJ{y3TB45O2om)nXwuR~tMmn1p$y zTxCcVX+8>+QTN1a&?iNG;*jbTCHi-pKrsIrfx21n5QVQi%yk|2Fd=_mQ}v#Teg949 zjAX`_SDIw$FrMgI-(X5h<)SV_y}D-#oUtNiPtr0x&%xozP*O27du+;7IAKX#4zT&A zjXS-M%XTLcMVM>#{KX=yhZZ<3&jb`l|JU~a*T0yzfY*~&qNJ9nqAd#PO1rj|kxdg}m$W~Bp>gre7s_)2w2~kY z8-$}BkCP}w-FKqYi+o&@_!1r)8}zKF)3oUSdngVH8Uf;ykwl6E@^Z(wYABCNV_>am zR%HL)ydNqs%k<8_pTU(^9{|EnV6tX4yXm_+8o!b!zOdd(v{B`I7F22lZT*lXgY2%o?Pr z$Mw{sOM>UtxkRbf;lZJy9Z6*qbHBdHQZo1{zu_}a@LcRxwzn^|?nqMiSnOsK^_+`Q zxxuZJE>_E`nsopDj(NTNC5p|)ud^-Dc^XrfJr>lqkysKynge;%prDhdGQUSMbM4G^ zyowFdye#L#6w=0>L)N}d^xS-#W73C{c3`)o=VH6^{^0S3lOUtNpL_*mwXT+QcO3FG$ESfWAl;(` zF+*TBHpPVmgRVf>a-82$2Vn`nrb|s}h6zYyr@UThV-n7-UosTuG{O*SE##yJ$&w{n zKIxyvSnP%d2e(BV^96mL1%Of?nnHJ!hf6hm!$p*9Re`(E813RI}FNbbhb0B+v3^d4a$s_fOa5mpI*cz zNyurqy=b6dex^w=PQZ>#8=E*-Xx>#U+3^7=*?@_5Dk`9LzJt>5&QsT^1~yTTxtK;@ z?CH>GZXRM0cesZ!VqC!N?_p`I@fngH%Q|7EU);6PM!2QEyKOfqm>m(HfC~ha=G*y{ zK7Y*~7q{P}JoafegWgVNV0e3pa>G zP&$AplLNH**W-)1o&{vyc$1Asf6Wl8?^hWc!ebT!rCW-fmriQhR_x?6OU?CD9&oibHEg9q8ued6%W! z%zIdI{9-puEnQgFpxpGfr%jmx0BOrbE5h@%n=Z#m_-+(#omAWksznnHvFa zYi6VJJeSh2QxZo$-;$p*>vIfOxG_m;J#@s@ilE})U@JU+C#egWe33)3M>!qeLlxTf zt+LOnkRONY+_#M?-Sy3ba~aG7a!uhiZus&?pujA`~P42X{hmn!5*n3THP80MMCjHEHO)g!)vd@L@)8KDp zR#@UG_0W(haj445VA1;U=cz1&UncSw(S#*-XRrFPfn+QLp`3+g2FG-dh5aqEqRSsH zWCPiP>Z;E~2cUM=wfNFIPd0Ri|5KoawxlBi&-LrqG05kcW2AKqw@Y>;EsC=JMC_8R zTVuWz7qbIR@-hqc3@)qYD5w}jfWDZ$wR2fF*R;N>ThFJs8?b@xMXHHUSyrKVx!|Ov zCWaIZh5^Wdl|tY>bdB@uHcVS))gLqEQ_WgwuRXx|dwaPE-@KHq*V7o4-XJC<{c(Nk zbjb8MMZY<67@OxSE0cQ-nZa+S@PW|@Jf`7N(p%vK(eMUid=JFu2Gw=0{?nWKuQ181 zO$_X&pp8pqC+bz-EO{G0^FFRuh<3Y)6E4y>{`Syi5c(;0tY8$rWUxxzWK z5yWx-zG;IOdRedHj^fDvQKMU)K^I+A@uOPJU|AmHTCawY7`TE-t)HUasFk__>gzvR z0I)~<9u_zm;y}ucN@$u3*b!#=bJ2P%j*0XlXU_gkyTl%9G(#7j`Zn~ir*1UQ1qZH_ zSzU+l+YF|;T)j&{zoD+>kY}sk2}&eM){4Kt}Q z&!;wyZf(DV_b27@U2w}w9sV7l@^a0T-QdQ(W~XvSTm9*H^oRNPgAxXA!Y-~x)T>@X z)>(87y)~>aWdvXJThoefkPOWKSgsC4lIJPnUHis27koIzf9m{?-szwJjmf>_caPa| zZ~pln_ni3~iN<$iVd0A!>{xK3MhqA#>5y879$U}K0a4uV1ATb~dSNKD9T3Xzn{+Elk6~4D4(LJSre*D|MIjyUJs^f*RA-8_0LZb&@$rXA>dxe@#cpb=;@ln+J78qlo^# zb2brbF<>s|z6dDV#5@TmZf^>W-d^1p&&!co_EUr3)4ReygMG38IbRh8MF(vkS5{2@ zQSf3mgx`O~TG#6c3pj8&LhYTT7gmaG-0E}@%c_nyt`(Y-bM1bH7RJa1-_DmOmCwKF z<-bDWoAZC+7?7F#`;kl$rInhsOeXOLRc^@XZ)D`!a52TZ;tBClCZ1EPoq)Un0G zs%hV1Zn+@BP6i!#wi}E;LQ!YaweWBGB8zbfV zx^zO0pNOPZBnI+(A|L9FA$=4}!CF6Cz&R9%wB5u=dg*U#&ucJyyAQ|RUk|Z?ch<5O zm{T|BS&ep^SaOO%Mjbc1Y}P);E*$0KJuxE#*4rOnEO>MzLQx>y1OMubyRDd`$Ys$Z z-`|x(y%ELhz|AfugA{Q)H*w-pw%bZBh{DzftJ}!}{m2t`vgn7z->e#h2li$UZu6%@ zG|$Q*bGd&B5NIcAdUxdXvR}opQi(C2)-=v1YkQaKeJ0{>0)xH{WDR-*8odpmP1f(Y zPJ2@`eALJf0k8Jgzs*&O{jO(?TedHh7{c1j9M&%||G<1Tfx0SxF!ov}Q}tPEC1^_% zt=^-!u~WEbHVA30Q-#&JSpV3}s{4tVYojVME~`sJy5AX>(tq&c`zwd>?GN?`dNSK9 ztLiz4B^Pc`9KGm0hRj2FgO&1Vis=|ji1m9O;O2pWF)qP@-y;DBImic1HFzhzzPO(( zY__k5)ma~djcod-0*Q%an+3@;$6%tFZM?+Dm+*YONPJ?Gmw z4|dkV>NE-Eaun#1>|H2FE-J(WQ~_Q1vgp`lIT}9mxJ7Qm2yfE-3pXl@gZijDQ`*r} zu!^qG;qK>3HFhJyK!y!nj=5E#uCEs6)9UxS^nbldr>$P2)AWsNXPWcGDb(J(t-2NLwe?Z2FEk8)9t1o9^OiNLM%)tFPbiA1=5LPQ!$YPvcS3;>kPxl@|nX}cgr(Bay|3qiq= zmZJj|Jb5-=C0tcT(7*XUt*}J#Na(zLEs)Qkz^zrC9%gVF$B$LOt{C53U42NX+eh|* zLknIEC@_`PPYtd=k!6}7En$@M@W^v^`MuGaD53G3n!*Pyo}|HYqy&vDm~v zL(I#VoTQAHM|jXwqS(;P^rj|41jxnXnk(eU>C{KWf6WG99z(nH)k`$zP4i9VVMy6P z#uM4o0^Umv$YOO1x?-+p%6A1@d)*mtZm=+DukMkuGARWzHjvtiki8{P=94iB%82=_ zJVT+^(J^~ZjLvG_DS4bu);5){hOxvBL56&>iexR;KU}vf=02?atnJj6$pu|v*t0_B z0w})?2Qr379H*cecccJz!4wYCZI$yU?Zp92%dsy@cW! z$F;CA>%hI%NV{ysbIod~oCx1uCQo!*>=YVjV~@HW7fCBXx8Z4+MSP@@aV-uQF}H_j z8jiaR@0eQxVLw=wi?s^+h|Xgxha9YoHkVwxy;6r6MTj`sf9+9-`V79ED0W%u!b&)UI`Dq7W#Pv+#lpO6LsO3kS=I%!}ER0j2ybtJ@MY>phCJr{fEcg*?4qDu(+ z>UikO7P6{bsy#QB?dmc9KqzDyv9HKwqX&HaXJqPRr z&{z9>pmA+~&dO!CEsCsSRQr{|{RdjYE~a);Qu#rxKz5FmuRiOV-Wb-?uwN|gmuU*4 zN?|7F$pTXlS}WagA~IAu4f{noSv_=v73|fv8nu!?)+eGau;6}H>|Yq|1A1Y;n6^)v zxAouSq;izk)IY3`e%5V{I(Y&Ngx$EphYA3Ax5VBg)vsGqTBZxXwbzRn`AKMwIR@+k ztnjLVIas>HdO8YP(nQ-a*OO@JSo9)a&3*m~7&kL!5Ipc%*AS3}F53g~82;Tvg5D3u zf`EsOLM?JyXeJn1e3pKf)}XD}q*PqFT|uST$@q{^4z)>^%$IcIta!l6b{Y>l_{cjf z?%*lsX4qcJ=t=m9B~O>Ud@~7KSB817I`~|vpk&Jcq{_^!z+n^6+k|qC-PA%p;W;*w zyH_#uKPni2r$u}ZCTSa<7I}I*P&L&@sVlT~un>BsZ77%BMjrhR6{wJ?bzRN?cRL+%j@ z5wPz(9d)zZ%;C%a=2iBur$kHDMqvI28VsZDbc7k}GnmQwvMy$i=T)_j4*#T_L%C=czabMMXoTAw466f_QvxuI zv}35(2+#~vIXpa+JID$w_8Q0pfc8o|Yhzt4%|gs6Kp>|**@G4L+Wd;(GL>;^_T`&q9WgS3_Olfyh3~s`268m{BJb60)3CUsz6TkjBG5ZfDo|S zlq%t;wr-6}4w_9nKyd%3gSt8X8|FT+FrBBr>g}z$+Q}eMM^tjBK~M76bY6q!Aw{1VL_Gi?yLQuvXi84=%gBAbCWAyyUE>T+BOT!8SRSVUBLGoD zi*NSuk;(10Xq4lG-7!eyN@VlQS1UFyO^UjWf)L+mhrL{D3MHT4Yaf#H-(wtz<2KYd zMS$kMEV9c3?t|(N{L1dV*rsxyK-;fTL=vG2#lh>EhS;noh1SmG>Mp!>y^aBihharH@$i+f`(97a8qI`h{#VB+TGIqu zPbtQ1EVL=wmMogL2ciW1?1L1njGr>dr#n;bjaA!3Z0WFTq};b^@qZ4@(2maia#^k= zIy0sLM@O5Xi&GebdzP?jW=y&xxr32zV}Qy6!s(UL>%%>p`JN6|r{RKYcxYfneCdG~ zd`3$1k{sG+i3M3|25jtms%F)Je79R0SiLL|`ylLjjbNdLX1->s^KRs6gbjRrFk@|b zCG7VqeDC;x(AcfyvBD3~So;lC+_Vk&1_L1s=I#3a<|GjP<_d|DR>}%Mf8+s|y>1Tc zp=X(=O7roYYI^h0S_j$ru-=ie7O4=P^mD{oVEekE|F z_yDZHrh36kD73vguVdoqjhHY&tmC21CM{Of+3+ThISc$?yBbJM^*`3WXflRb6e`Ne zwHC;Rs%rIePMx;YQxq?^<&vrv91A*YY3e0&cMt({C`@L6u!MCVIaZz&Y*+J$_(bpM z2L;8?5wIsPyeZOJmcOe2@6>i{0PsBt5OY_1{3zD$ZH*|XRMr5f=82DNyV4w?l7_M$ zfevXLK>Qtbar;hVl{aRhPKp=bH`5|g%M>%B6Nzf@F|6p?$#s0CF4URdhv^H2=lbv+ z;Ge&|X7j&G$kP$gFW}~mclwJq$4N1-0voQOZ6YVm66{>7VVmiiS^j1{;hQ#IkKd;yW7YG*vBrOr+M8G7AA1g}g>5;$v8F6!^ z2{D#&2;A5VLf-|Cpvqn7X&?F(27Jt^k3u<38-yIWg}Gq&cPeM@+U!Rfg&gQTKM7z` z1`zr=>(Vcm$Q=gfaQ5^0Z}g3$*>LwGlK}F)p^B7Aw>`vsINwWkZ@Twe9KX$WhI2e3 zh2^wI23~vZFD~EJHP`-|gIVWW4sp6O&5crcUrjy3Blli!h%b1rO5PwVPb8q8DHE-J zI=4C4Nw;O1NE{ybWP0das6UDYG*?syY}SLcnf}wc!qV5|iT)SkpL37oTsB-47VUEVW+H|2t|EOGH_VFk4{Ts?_sJK* z$kM&B2e~g4WnS`gD8Y`G?!2A%@;UhwF<4|~f?4Rg>uCNFxCZ6@ikbUDr%{Ka!76=# z3AZKl1=ZQ@vPF@7(|I~eVjd#YYZd2z;{fdCN~cl|i(wWD;rmuj`# zhfKFuLywo-^Zk``UO>VD3z)T{${Fn>lb7d&l@t1SzsO>?qQ6Lc9fT$$1kb$PC;U-O z#|~F_=xj+@K8&oa*+OHZ_LI13m-_}9dG2$)#c0$ z4uHdqa@-wzE;`GKBJdwViR=+h_6vC$91hsu?+ALra46|aGH1ID#vdTq0I1Hs?Zipy zY?)ofQryhx#d3q_YKyznj&bEt0(IVM!iAP)1>DKhzM#L%fG{TUPwXoT-3;^b9bx?g80^Ye` zKXmv?3_eL6@XB@S-T;|#qU@^jM}WCBK-!2YJMkU&ksZ+!C$*WYcH^#qH&8~bt6Os7 zG1jhzt5MQtAxJF5p0{F7`SQ7kr0rKH?{g6ZA12bG=UcLiFURrX8S>gSQpy)fITB?1 zulUJ#mG0ahJ{7IbExET;jW==NE=FXf3g@mbpd%GrDwicZr$d#3vf48?r7pl78 z4yt?BTHb{7p~Yhd)745_cN9JcQd`S)Z&TTxFQ^Yo$sDJ7)n0X;$zMW&&WY)cd)Lhw z4Fw~yt)~B}=x;=P{RnHITJ|W)<#c5F!(ZKV2*f9f&01{dVy#^&%PJvY+#~fXK*?v+ z=l7?KrnK@ix$Fv&J0V%3I<(r3ExiDfCgOZ|*be72o@cMx{<)X28bDnT!^BfO9py(8* zS~9P}W~A$khEyQM?R*%QYu98{YG;=t2yj2Gwv;;-y>a<61H4kS5#A`PUkcWhYMx9; z0(DB$nOf=qRC3w4iuL9Xdq|&-D5J@Hn;-5>fK>IHZ;~_scjEfm%g%PGk&?ji*oIx3 z8FKRVVFx-aHnf{HnQ*;DI-U@JKQtq<9WRe;{S^kcxxN0FZlwYcBhezA!n zdi+jn5>UAM6Jy*^zue7{7k+D4ZxZ6XQ8S$=Q6X@r*E*Nl0R+wk4^?KvfLu=h=G_gP z;epRMaChBZDDaD!^u;y9U?u3Q-eo>~g;^N3H(9vH>o!qt_xEjX#t|TOaqZk*;4lGM zqUXwg2b*%n9&(18*o+oFzZcEE_dEsveYpf8^}(dlCIHBoC~E@l2sJk`M1fEa%FD5T zR#`u$$w$OetIhMuq|}LDl`7`H7sO(AYSb}vh87_f538}_0r&x9%_*nM)$YV>+-rAD z3VHl4ClUF&#&9*;N9GD(NLEkqCyU2Rttd_hQ*o87!@GUs2oFYs%wkP+*5L@7oDAVt zl7R?^7i++T7e)dIpV{ny8gTWp9cy=N7H~Dx9Q$DcSD;dqdws`!1cf)q~b{VmW*A*!xuqq>Uy6pbIq!If&?XbI8j#YF&j z6U=IZC|a%0#=~*4m1e`a7d$W@r0G$eL-OgP=q-gi9!drW0X#nXLx>4KKYwo$`!{_5 zjlKk>yD<(Y;irO;=Zumz3__f{Cg}1#b6)~+AR3LjfZg)q)pHj0MjXe9j^jFN;k&Ca z0OcX&tOjrPCr#%NZcmkHCH9iqNHiDOAKrd?cw{!~BLNKb*pu9s%o@nFCwBt5CDtVLVJ7`ZV0fc~K$sg6b=d~(#l#1CwyC>?$bslLd!<03E6qD%PVo&K4 z{ts-I&RZdlU+Y_Oz+3~Qje#En9CYsT4>-_#$K2J1qcTi2Mv})345cu?@REN=^NnJy z0N6CW|0<``pP!`N3SWGI?x#Grhu|?23aGzH*s=4lkOTX7Umy#70nr6R+;Kfs8ZGCc z%`mCzG+1(+=*%tWpn@yT?|+8h{QcCwe%9&?>A?qV2eR8OV_x5U_YSf`2y+&!6R%>A%vBjg*#?_D^|$RXNB@anb+JB*K1zP5zx4CQ3bk z+V_Kg>v+@bQE`?GKpREW!p>xuKUshR7T|R z(d#S=0N8Haq`h=fVm*nc<DD&*xTeAfHUv{F;hFv-YmAc)?v|NY`^^ZFES5 z9*81Y3P3tbE_~c=5e~)^zfGmK;pePlZ+vzTiVwN$+ zGur8}VCJ{L=LIt0t;qVQ>+t&{!OkQ*XP%r_!!PR{A2PIC!0JalZ{oWRB8A6t&gIFl z6v^X@u@t3Jiwkn}Ygtf0)Fm-g5rX!na=W?I8Cbta8vgfCwN?NNXq3ir%#jdBcp%BQ78G!o`-+Wo`5#+j%%6QKP$R@g+xLEfq&=2Q2?VUU*XsAv;Pd@PpX@w zPRXGWxiC@mJ2xa(^~9~;ZDkE$dz$4KYJ9^NsqkNC_|2=FfPgpYHYdh0MIb_a`8%m$ znC~>e)G{SlL67+Lu+m%pjsmg`oLC;~0bCLMSGlggdHM$p0P%0aG>yQ4kCsV*l<{yr z{uuLS;864BFCqW`&226`55@HT{1(WsN7divH&2i-2c`m%|HT&J83V)M@5bE!yosah zo&In@s^1d*-FN;;4hjt072Gh;PyAJO>F;sI1Jj^Q=5YAO7NPxM$lTw%;1_Oo<(ch( zhyw@;cC@nmj;2EgXl~TYY|XtG5d0@j!{4SF47?CN8y_&UY43#YcJm%6u|V@3X4$`6 z5P|>hY!ie`4%D$<4E1mO0rUNN@dndt2N|IwOJL@I^L7y<&qMKo0LJ`pXUy$iE<(b; zpRx0Qxd_bAk%2xI`2RiZ|BDL*{;LhppzIR{YF>sz2kbzLnDakW^OL@GXqfurmn4(_ z+Hv;h#lxDY<=i5yL^r_s%@a^Gfw}FF|I8W0^F{{zo2gx?1kP{2aVcIau1Kk?!tcJ5 zhaNaI21bDOcnkWi^)LbUVtlVQH}Ld-AiVs&EnEPt@1BmX^Z)yY>l-k$W)}p_2zdruY{J;}b{eSOE7@+@&-}Sc<9e!3BngQYeYhMC9eY!C}?C(|l#TH0? z7AY%dEX6)YD)qw2IjVQn@YY*5Qf0yQR>0kY;B-($Dy#NG2 z@Ns?nkG_bUfN}zvA!*0+NgVy+B=yv#5>MUK6qT!@$dXzNmUy6CKnP+O97F0 zY+0VncoHSh1h!baf~8c}{x@wGbOF}W#;SM+u82ZwDWu3=J`i$$eI2}J^o}qX(PZeC zERW~?xI+7W_&<#l^z%HwpR|WXOf5I${Yf6VqUb{XQ3aQm-Ca;PJrJxjZNq5S!q5zeU@!aRa*E2L{DV5cs z5Gd>oHx9o3MJeJhW3}{5!d}f2Ld>MlpZ~nmU}q+I_VfkBZNCA!Z?unn&PU$-QS+1& zZ<$mVPj@Hjc79;Aq$(&^6n88Epd^g}-IU6kE7~njKWO-fp%kv2d3M`{m_C(4tqa_} zshX-7ppY$>%4324N5M;)mzm>v!x9&X3c_6l_#%bmkroL+kK<6htAOT$Et%W(6}iE^j7 z7meZw-NBfNDQ(#B$O$#2$!QtbYQKeo;B!;w;i zs_Fft$3m1ST(^QH@!jDx>z^zQo0`ly3bjX9hgkriEeVuXvyJjf0g+eD zCT+Z|@EV;Zi%~H^#5)%guoOT+uP&zS{j5h&Vw%L{b7>g>B@i}g4;nb?FVpdIFsT{; zCMKl^dT^Yb_!%JlXQ$rJ5}rQUArL8*0O?i9$vp)yg6Fvb{qAB>V6k3{;9TvuWF?77 zUKjm3ATK!R2zs=b?>GNT4QDL>)XIM6TZdapR~Sy;c|mkZxDrlU7%nk@Po3_!0d#L> z08|$kSDe?~gYe<@ax}0+sbjie6Cm@L0HmJtPhP({--mxrsnB2NJKM5|Py$NGQbD-3 zAY&dd9fb6%1qJa11i89ATM#yz_pT*!fRIzB3O{``kfiJr_vDWY;HMeuSCLN>hQ0(M zee4r@%iY<1VU0@1dR=`qBwC%z=<}Uf@nya5AAr7r)8hXNRj*X2Z@FRskkcAkRp2T({*A)IJg z4rDSt*mg_mgm`H(-t}qg@|Uo{|6I6Q=bvNudw&oxG7bP~86Xthl1c@TC)fzGzr-tb z3>0iWAn0tw*C+@M94Adl17aNKo@!;fv6ifRAYpu^@@%K0KMS5s1-kMNE)O+o8~w0p z`yKPVu4f`&;0Y`~$z^?(z?-holGiu|OVwD`JOkBs$Lh0wD+l6I^{1Od;0?CdMLvyeapz7i?oUp?#1J@SKedy=q!|4{PBszBpB^^+ZUY?V0zK36gB6^2YmU` zrv>PzHMw6U?LQL~sgx<`#lvx}w3^32zVU!p>|Pu1fX_!~SxanXyX$97=qy zd%kB}_cA~$pq1MQpw)D{942XuXL~ipmjJM)dg(+qD+3kN21dXMSxl5St5m#B-($BX zil^7BpklX~aIY_YhJ!R)&=a}=aEcfzaB_WoRN=ixPH-iFWY0Cd{^xFSgbDz2+Vz?d z5ApTr@c+o0tTMaVfdSmxGaD3O3_s&Ti7)nBXe@0BvYxB$Oh;h)VmHVFw;U;6>L&M3 znCO>pY4hY#;w;9^`fiumK<+dJsUp#2UhnQMkK44=b{ZecJY0Uw(86Po?y zf<}P`HNeH1)^isn^S&_Q(SDKlcNp=%=ZIRH0NZeM5juqpxG!Q!$G>5!H9wAk?bQp^ zZ6(8TIg9&#S&sV8*Ag=RxeSz}&shk3TRtKpq35%gTGivo#cDU2WY=gqw}JYPalVfT z(4%N$wY&5As($$a{PcKN=6E!wlU79mG^Twn4OuMy2$(3;=;$!}T^^0+IhD())nxMj zAhz%J6FO)9Z;HeHI`p^cDHx9D==uP4y9uzkW9DVyw_ukL(&xUl@@9S~DAws6aM~KX8 zFE9teKYd(42sm`4{y#8Nqwz%|5d%K=!0E}+{fZvbBH(DObR}yqpBHE8zp;GuK@-;xMhGHtt^;AO`Y^PD6un&$iet)x4-B0;`nZ1~y+(7bpJDwQgZ9D12 znBMF;<`)RxoVSO{niHwuywy=kdPzfC;uq>2M5&!~SB@6lnVgp(G-?mb9`s`9by?)k zHW-f{3Wc)60-ul%g;S{$H7ZRdC=u}k`=^YiFO*c=$%;(Z7N2hKMNaTwn=f1G2H`rZ zB)Y08500F-5$sMq?vH8fT@T8=tY-D{sl0lldON&J`&tCOrOp8Q^h*8qqU*e5Gp*g} zg8N?XLL(|wfJ1I{X8qXik=8f8c<68KIm$kvQTqiGl8+iL6=Z#YM#=R7qTCiQC&e**>IBcuP-sE2(>k2)HAb9?j*pAW||J$K*-H%G$Hz zyKUDdYyEg{`|wHoD4CZQ*}x!*i!jNUMpMRqx|Cj{UromT>VTI0{N$GZ>{yTdKv(XI zZvd&yQKQpU74akFkuC@Mwzp>XQ}_a>yHr%39I-{^X2bw#YV3VkBjxVd*0+|BRT-F{ zet;?w4rtX4g7eVEI8IEG^d$NQJL02UeKI9LQ`hFNe9`}n14*MVjZA*H(SlXAF-}oQjLsatRu&V(&8IlQ1IsLNyBVUT{R{Z$f zV63=YrUuFY{pmc}B-J!$e1FM9L9L5Qg_5+$_&(G4aZQGKj|KcDYq{a=M!wL850}WZ z_6LcRo*K3Qyi1h|BkWBAZ9i|t5pC)oT=JqP*M6P))3i<$k*6E1Zj&~GC&rDlZ8Tow zaSQpID8r1o9YFw4Xc7ACE z%jqfg{!DR$pTgx4ToBb{&svY^q0831DA7`n?GV4Km#no^@H+N!vRPYAx-hTW+c=7N zkDy_p!9{Qa^Q2cXyPE6hv?R&?>5TLN^d=zKQjg7z?Lc+Aq4HC7_OPBnDsYeV()IdD zb3$@nQCy0A^VGtGPER@6qJst&{F>jz@9xyo?9(LLbR{NTajBDieYY6ul+d5b<3-|a z_oS1Q)GBYUT#(VSzm-zVf%d)HHWv4Kx!Y+!W@k=3xYp9nxups3zIi_StIkcqaZ4ns z64?yzb--6>pJT8@ z?S2}re;MsUyE&G=x__%<+8d<-K%Pll!CN0)rgJ}2n8i(0+P~j;>S2Hq*$gqaaSXdZ z>o6cb5NQ=?Wg?v8$V@brSf>X*SkHzwU;2?1KKx83(nO%z;|4K`*u9n`#eA!n^X#w= ze9kskV?}GTY(q+^cs*}3eg-!*ddydJm0$TLXzQYsP=5R3=q93(l~77TzF#1#&90%7 z--gRUAbUy$D+CO&v}SSJeqDoU-%oCbK5f^EhV;owS$%GbZslH9fq4jG>HI3sM1bYM z+ixQ$e(e$w@A8P3kk|cUGK@;aLryI8EzxdG`s`@?-L6FUh3C?W1v-)^qpb2b<^Iq4 zTlZ-qP+V~#dr;-gk{fsNExkC3rUDcE2=lkP4)vdi&Il-2mYmd&7YoCAt9INuFE`Db z5~!3~z%J%hMQYGDX2Wt19x7%-@ifCRqtiF5>V%ZgBHwJakxA!`kfH=tC*!)m0lpX94mBv)M==- zi$6FxZLY_f%%ZlM-9E<`K`iy}xe&g~=~~D+KWBogh*AbB*-?Gbq3fQ2$si$o5&3{A zDf`Cbx(9Z)(xxt%)48pX=!F7Fw=YzPaV1-IvL+wSX~9IH3a@>jUm6fs!e>>TWJ$Tn zDhVj-;6NOJFLQ8lQ_h|6xbDhiG#tcQD#*|sq)-p_BFLvquD^Nj3HuhjTgr8$qo#`a zI@}3tfsz10OD}vSffzOw`x{T=f#bY}(&>~J3V<}wM81YzOEn% zfx|-`IksNXfxCyOMZ7dSGqbC$q$}MFnU5tbL2;K9B9v?5tVIoiiU=%J_)Jwkm7zMW zkqCNj?S4X1eiS69F|hCzFyt&jnItkIn{jq=tBTt`KoZy`7;60osnYuf%Q#UDL8MQ2 ze8dmx6Q^Av0za_!GBJ;S2qt}7+CDr2Y;GTDfYHam3A)MRktK-`kUfAtoV6My(K$UP z%BzkTz)pMj5T-xHaq8%i7?4N)5DA-^sq~orozq?mS;QpXHa-7qiR_G!pSel}ZsQyz zRES~*W8Cr6w}Y#(!nL%oAf}LMi;$o^@~~Vuu<0p}{daO3=NM=4EbPQMrALExijSvb z;Za(h2HTBKB{(v|{uJ^ptLG{%$7~%|lPfv(d*(P zIW61vF#24K%Mpx_%x;zX)*Z%W#BJA~zd(`L09mt|5>JP{@IKgr?^k8Ij5ZD-{0(m{ z#!;(teWjP0Jla@a`yP?%!Ay4rd7k}{E@yjGH@HceMuPC%8mQ+pp z=gG_{nGQ1Xdw!TdA=)@id`YzB+cXT{`)}T;1O(O;I6rt5NQJkJ1xJpOH-wexxxn5TT|a&bb~~>C2_seP zj_2gUVU`6+n;0IUqAaVF_2S{K+t;Nza8FnGId(qID=)C)huKE?#h-&Gh^wC#j0!b) zI6oOS1hkMSKt{ScyQ2~#xG_KoPGKb09dd=~xcVrPpJ#ag&^S0uQp+U!A%arL;;mXI#Z3C_i|*J0Iy0|)u&uNH$bKJh zbN<*New%_!BI=hw_z}M?U2=C9qA{=JEca$y#&>53Xt4EwSi{K!biU0o5QgS}iq%+G zLKeaJKG;59kYq+aI*&9B=9}DjH@LiC=?V59fBt>_G@Kt?(*erwgtg2`+}x)oZJPpQkV_cDG6Kqgs! zBiRy>s^tufaLQ#x3Q2^~s4KlJ1S4Gt>g;{!+tC8EG=qgFq%jJ3qI3b}T5Z-Z@%%T} z*CV-M)U-Z6_n43hn~h%!ylp~i-|th3@3h`@PgHwYS}MGgB_#C-_qt!BP5FKqn%e9k zy^A8AeP0*MbT^vdg*{*b{%t)#Grdt#J@x}2jr54Q>l3=_984|rJ@b(~y2|*aPgg#)*NY}_K0<8FC77T=U;TKO{XPrP7$+HA?$;ifTxivB z58p3#SWRTGQ<%zIU{>+We%z6K=JU9h7zN$bfcWB4qA0dk0=m!r4PGmf>O}1%e_$-c z{eIWtS|;k_;c_~c`3YK)NKwQJf=Dw41}*vq%ASN?<5Buef6>)FrJ;YBI!>lSAEW{$ zRRg~dEQ_=NVb7cpxK?NV+Ef}V+O)3fApCVPF0%L81|>GX0Tr+7z5ku3`CN5I(Cc$^ zGQnz~)P~L2Zg|z`ekFG4b>cFs$G9is;qe{Lo zWc%S2+bk=G&}SxxPPKTZE0kC3fIb&X^5Qtaj#8+#Zl0)DniqKZO!&08$ZhVuJ*7G) zG_6XLktKX*uf)YrU?dNL&!742c)3EfB?yhu3Ae-eSg$3wjz0DDyF|qr$AaL4kHt(o z?zgAG{d2w*)*BKzF}~iYd5|q*u>@r04Ya9vst%7da^`Khmr3P3Tcjv%#mmPQm9o%Nnhu2!!%K5C!aUBa&!$DZt6{3 zPU%;=c$KF#od&jxE?XmuBWpKB4bpy9%8QqFwD$E! znDJ&|P4&vLH-(4)$;9`Mo>Ur{-xZjO%7GbX_RVKNEGl=x6b(jC($#K~(XvumH}Ji$ z==(_*9`;s1EuMC*tsQachI4#ppnCW?)p)ar0oA6%B{6I{He>qg$R5>+!6XlpBjM@f zsASNca%J_Uo7>}?CLtlGYV>k?TLJm?E>~U%pvt@yda^t0}f) zWb78YM!1!ja)4S=K+c3RJR0+JPMku*l;5~wt4vK{OHJ2!)61+6c}3h#&-cK5`>H%o z@O)MF4_-dk0pG(J-6mG#2XncjI$2j!}AH(nN&KE3hPqyGYCE|TN$;&U|TD?Ys z25j;5_{+@`zy}BHm|cXBI99>K*GXypPefuN2IJ%_FN8W%MMCkTJ@rH?Fm2F}df&#w z*>5MoJ;w8SmEX&`gEzj4LHz97kcJYIi3r)=js#7mQ)@c2L48MBDSQ=~H_R<#@QSC_ zL#^lG=Yy-`Jxm&PCaJvS=nRMRT%$1z&#@Si5kjl;c~OHi#jEku&{V3D4n7b4-2P=A z&tmio(8W`WF5V5R$48%yY3b~lkMQj9JL9hQVeY4ATdZ!M?%3{Vk&==)1L(6`2l(9- z^AvPT@ZQLSvVMYs5-Gmw$P9w~!scEq%gYa^Z92#nzez}W^z?VVgTI4^jO^yxiZH{R z;V{@V49(J8m|n@_)VP=1xJmxLd?GDzO<_dzgs}c1V<(L$NN9BMbzd$Ofe3~px}Y(4 zA7ACyqp8D&7@C3$-zcIW>k9io!a3Ko7dI)cKQTR|Ohbm@bRL%Rnq9QtISbjk4b_tE zN7O(ckDcUfvoHyT2PCjX(5wYE;gSyt2Dcs~R!f%)YsKw^{@l3~7Hc5$6r&x_3{dC+yk$9Pw70o|-hw>fz-Y1(0A zsVgE0e9aPDE-cxp^gf_bI1EAkb{IuAH6h=$kfEw?sB`3S_b{KX*?1=@`uIj1J(RL4 zpyBsp!Ts9-%-uO32krX==QuG)$xG`ciV)NXURxli$$ijEQj=Ma(ErgckpsnT_dbe4 zAzyGehKF1NHnePDAP@?-wSnjYhb0RTE49$bmBSLBtumV|#Y+K60(Hh(U$Jo9{-XWS zEM}D=&0d8`o}rHQaQ9$0@*By5@ry4&Tw{ujyw0|0AO92`j z@YV>QoQFU^9+?JbK6K{ly1!803B*z&Zfk&d8Cq}=)jEhDU*($<|3v} zC>iUNRO{JtMYmPU;5Z_5yo1HBwl=!-Q4tLMa+ z@;R$p35=>HZQ3za+kXT)K#v7Zfa&TkHp8q2%9QO&b0`DXd0YbuV@j0hgWvLg;S0W_ zm|vcBoqw5%#l<%O-;!#Ai zuhA1h(oV$bfuGWRx}bmz=`G=DX*$K?FJhQL2=SuoF4TlQDk%P&y0X@IUQn!RG!Uv@ zq9W$w5C@)zklwNl+>#>BL)kWkXp;q@Fbi$MkLSCbuZ1N~?ln>qM?B^^#Mn-)A+oeR zvU?CrLsk_kJNr02j@SG#eK{ry)th52gpB?Mhb;@uA(qff3Uq_l* zf}=aqSK(y!+}Dnh4W=M?nvv&Zc>7qR4r`EC2?rmKv_FrLRC>{K^{q=LTa%$}W&=gH zM-ca70ns2y5D&=Wl8j&ch+hP_EV@9gVx3-vKl|=8js=TrbK=7 z*UOyIsEky%E@`|V)LUp@;~+6wSB)vy9cHsZ4%sH8RrFNzqYs`XF?><)25$^EJz0_& zj&LXrT&`^cE|zJ|~>e@aIg%L4K^4nn;%u(MzMXxB6WpsT`>>qt2~+Ub_{rJMUy#vCn$P6+6B4w;u;!iBa0vv z+D4Tq3^EMu8FQ22WFK2!_fJ)j=iF2{>Gv*#d%Int9hxf>kK9`TVjRUbCA~(>Tl&hO zvea<&H$^7ycB2vALzY!iEvZ{ARt2;`5!ZmX$fsO zb$dkY(qCN89o9b^s%GPi@tB$R__JVnON^u4R0;DXbvl76n3G2GI+587pPtR29rApeU_7B-ay~^} z>>^PTNj8}yZ0o5eLX9~k0RcdafZJmg7EJ?sLz*&WLjA_9lh^nFD!UT{lscgiZsEnJ z*OC4N8L(5{Z5Fh}Y$5c+ERY$4uNV7BSO%YtOT%dg1b@`pCT;8B zO9O+G^9{xUk2X$xJ9!7_hP5HNwDj1>5@Gq^BxXc*8)x@ zU@-+0lC=ighlGOH97YJGcoms=ZJ#DkpEJohX(0L*+ycWnT>uQkS+(g#gn zfV_)GhUG~z?BK`@ut5diHF}d|iY%sbi{`jdzhW?ise&9?QJlBmfO6dl6Lj&a)*uc| z=IW8INogY9g{ypG(6cn2Lh)y*PA3Evad||i1~YmGB7-D<5XaLl!>l#!NPtHRnNaDD zmc0dPEZNt{Tosb5nl~b*WPE#u?dU)4&cSsm?oSOC*rudiyS{&5-p6?XW~ugj_r2_7 zQiZ`t+x7?(yPXK(R190_+Uv8cN(LTu$?h`fO9awQldm&QD(VFB&*D?cK4$Q>Pvm8Z z_mMz%xQ0_(!sZq< zDzjmqn94%dHa~w~!nFjxhnJ&h{C0vzbui6Fse1JiyZbB|>Io$+p6Rr=Yr&g$8XJKY ztk*ogkYY$}_ZWScm35vDgFm%133v8@B zP)UCeLawhT;gkW^%VljX=ce>wCZP&N=J~#=F~9oF*=DzM|GR~HBz|{b;8WHjKl_Al z`RL1#QwB50cF8I1p{08EoX4emP8dyeA%Sx15{+0r!-|C-dEx=;_Rtub$2!}}X50wB zoznuNL|0M3_SG|(bw69b$2vQv@%CfaNe0T=A`Lt*d}dFvKK7rPuoQLFQjL&oTbCOy z%)>g9|FMxoqu*GbiiBZbW8~~mDxp@3%TE)DlMqWP{`wdN00`JZCYXs|rvleRtE zk^?0m`C;Mp%jlh&f&q}9!g+5+$Ie(gzboyGd3+PN42|5K&h2Rroj9y^Jb^N;+bH$1 zqn>R%k4yv4*jFOFm3t;IGF2}CZuppg%Ov5T-Ccj&*`(%5a`lw?ra_(V<+em!v*O3Y zhntH7QOK&;3>7p%G|l7W-a{bIk0F3AxN+aA2pP$$3IKQ0Q=4wV0tX)52-oRoNZ6Yo zdGs0Iz&C~a(&+Z&m4zsB%`I5f;>4)6h&OY=Bi}#VkxpXQr)|IBJU8q1i1E3ZiG z8Dm)5{cZ_n_$JQ`x^DfGZ3$inj%k+SENYMB4v&^d;4w|mDA+c3W&@4}d-;cFpkl6s z+(`QyOGZCJ-(Cn1-RB)|!gmLUU^5R!F&b4B?QL=71X=fY^rhOFB{eOp@z~{ zsIj&i{Z_Xw$xCK@kJW7{1CaP#u|4#xYUT$Icd>-~3F`t)_)cD+vD@NGr7pOwf6clD z?p0l(2?9?vx?M#{y#x6`TWg*qT9K!P8!?V<8L}xXn}n>>L8!wIpvYJ#Q}0uoS8dJ+ z&Cch(#~pjZmzGz$pa?DRYq|%n;j_WOGfYNWlcuhkW*X=2yk^|0(q+aL2tfET`^35e zdd_0C-IJ_tpinr*4{CdmUwI|o!%yJIW3JSSX36HJ;Ptouac2rJ9$LJ>4}sTVDYoWp z%JN8?J9B|nD5o;E_b&xM-K5>{nCU}CHoMF=$^jLV6t{TLjof%$_o9_EZuUMb(ZTyG zoAF-DD-M|yn<6zGEdhG2PxzfCA@M@xJB=knb=bY8=V63Nq!7KzroFEQ8zU*Y2Z&)Z zRXS;oSqyGR7SD7@SwwhKLqE#5)QjMJh{0U1_?Wx1QE%^9p4JeOxA0yq)tOf?CTUQC zp@R&rr<0bI%1UtZK3t3U<2Pwnl0eT#_2rsiC~U(rry~ zcb2Pb=m8=^TW-!!W%o$XmsOM_?^Ehj*3d4R)v2=ZCsKhZnDWK7T#d{ByXuz`* zgeZ^&k6?ep5zi`c`0&aPD#)*;^6Dk39Z1?mnCChVh6u40PFf=th?5qTfjB8k6Imp! zg3IlkgE;VZbiG^Ng-|AEMcm?jur&m^@Yv3|8hL-XsAtNFEF|{@5~wLEMGH~C`Mv5< z%iwzY=}4pnB9^31?b~V)Ay+ePRjmUHWVx3aqYzYR+Dh=L`$)|q1|e>+{c@-@fX-a8EAHYeK_S%g7U z_4__s7{v@zK1XNJt!sQV#glVw7B1XlB=MIz_hk`HJB~y_q$ZDD`Efw)1>;;Qo=(v3 z)g^505pXGbOI+lJ$#!m*V>j}p<0^l;F`DP?oZXWnb-sLinaQ}_E#Bf6EcJA1pv-q- zX8cNiV$|=3Y|e25zvbr|2S#s4CP)xz721aZUd@<@nf@mR^o1{8*)YA%N}GjOey0;e z*K|~C7l)UJK&Z^Ccerp|^Rq+~;C{@Hk}9=$EDJRhz(Hr#SR2k^Ye;Z?VQ>u`ba#1H2y&x*z zohn2kcVoztGpo+6a(T_5O;uY`a~0UrFWY!H6;mn{M2RBk><1=ZUy9iqh)}TAgp6ny z>{+s5GN-SON2@}%UGxmIC5Ks@P^=zM$gdC&GMWw(Po;^$wnQo9-Da4>;AK1tV%^mH zFNt4fuF2R4^uzt>iQLzQa6R0{%uOq8FzA_>$5;AB$^#5e@3?9*-QAtezBl@bDU6N9 z!QcXTm2Y~);Y`WIS>A_WxAqdSJF z0FK)F*-^h$fvU1f^)C7u~3q;@|!>5KFASz5HVcI8mu5>NlvpTw1uW{E1}uY0m}yg zyI=zT>mE4Q3QV$v^ z=~H^OxK}JwL}V}q~V=lHa_mK7yGYvVR&YxU(m9w z=r1wozA*};55-zVMM-o#u`?sNPHl4z(_L|{)T3Ruqx95#c96*4znO+3k`#}If?kIi_Cqi$4v#j;hR81llyz!lP}v3y#?#lRTi{M zeCAMs+&!rRS@h+Dsy#Ts-LiRc=JOxpX)h3u$F)qkP|w!(Odty0z!tagMB+R#$QM)V zsWT^hamMM%2cm|LU{EQ>?htNci-XnR)%#hKq&K}x)xwv&u>~49eKYwvvS4Fhm{W=E z;1zZd!(qJOc9!f^rQhsOr3@Te?w(K;g)armGB4_UsRxoq>$BtXlR_2|!Q*nu^Snba zPp`3^4BeY5DbRu5gmt1f!ell^aj;C&+m3Ec_#u71kdcr-&tDm%>#k0{c7Cy~{B-qn z&AKP(DU?haBy}-YkWkB%M3~sHi7j~7jy`&)^&yTh%9E=#9>s%d7S$QU`#pwJdB+0i zgn+a!kUz|@`Lw`g$|Z(g2e;u$I{PX&iyU&aH##pr!T1TQp$U^te-8UJS<9at4%)S1 zS_Ab%J`Q(vg%S?Lvf7D{iTvwN73SZtEZE*|eheVAWW9j_%U;gpziluO+rmBs5@^V# zNFvv#mwIIgkkECN`p$-#M0yUWLZ>sfD<_e}{iAdB=6)C}KfgvMU>irn5~(?Lb1InR zORmufl0=`JAjWgn*Jvm^zI|MJH0HYwXAUD42Y$8Dmz+^Hya?seIGrfVA(L0iUqywI z*ciavnS(OGZlF+mLui>j0ydgb^39hRWl~j_Nj>LY{-BTkRtEFPgE+|9pIX*YB+g6! zF-X5sE<%n1b6I@Ek#+1RTjBKLsfF_Y$Jkp&)zx&_!U=(3AspQ8;O_43Zo%CWBuH=x z5?q73YjAgWw}jw+aCiSU&)fa=+jsOGxBqblM|SO9t7_F;bIzq<`2mgha1$~(_85OV z`Q+tI=DcN~b)Ry{O1@KY%+HLR zZm!|lqZ4+r*uga4D59?ra13*f%l0+15QJLG1mX6U!#NL`G?Xt@K^1MXEb?XEK7-FMvt+>W6;bH2)5>E*${AP8$GdYGPrS z^yFNciPAYdbv`+nKDNhv(Y6KFJnJBWHfya$KR52AWJmRLmxbY)PCC3tw0SfxjldHE zIP0k%qbiUcaqxS39?_TM7W$N}S!KKZ@l-gl)0@cYLc3Ox(^XTlNxJ=Rwt=+Y#>_ON zTs?dw!E1@{3$_)~xWpT5wT@Y(a=2>>8@F1zXP%p7K|>U{XNO$pJ4y+67-$0JY4gg* z2*PR+cclIj*|aK=+>AlyhM&;SdN5N2w>3|g4#8L%|KRt~)Lk<=ker)9_r0?Ld1oAfhq11pziK&5(v6isctx1FS zF|HmpPvM+=jD^Xwq00Of7u5Xh*s?z5Od70#+mti9iV8>tG~yIXlG@yI=1U#NT}@9637Zd0bJS zxoe9>^!;Pm(V_T7IP&qcRY+beV>*zcFjjipE{9=x&VAE>yd$-VXeN8O`%W=DQ&T8q zi6ssCT$r6q%<_<4;JdLN!W$L~ge!0AY#wEy9_gJQ(74=^GMEW{=?OB8Oezj?lK{Dm zTrfOzPo=uet~w?&F|rtOaAp=L`X5A-1((z5NexJTto@8B1)r3Ph(*o9=?3vRcprr< z;|GT!q_g+9WaVVCEc5F+7%|Dwe;YbU@f+FkXcujm>8AKbo3`zpc}t&Y&u7u!sC+9K zFGPy)U~~qw=k6OcNX}J!s8x!_^(fwgO>3eAmEWMOo!nPWS%At#Tn-1`k<0)G3z+;6 zKZuk|-Cg)Lg6MHydltw3>tqL7_$vkD*F7&pZk_bf-!*oo(k)@4lokBBfhNf3##aUN zt-i##9sA&?sw-SOqBNI9)^zess1AYioGc(VbIL5SY6Y@H%|2 zY;}#(c)go^sg|@G0gFZ`SK^5x$NzDcL70rUHYh5nbq{KexI2d)pfdGh_`zvgF-5@m z78k39A0o-AFlS1i_Ml?+(fLUk`v1VX#dSYj)%T0|YJ{fKdywAf?fH_SfiXdy1N8io zUTDgV1$G?VluA`#n}CkVMZ$#r>$#X>wFrOLB%@uDAQ%!)T|sK?D8X7U{cht3I%XI4 zaasuP?>U28R&oZ$S$PsVnw!YRF10Y(g6Hn3^5>a?+{V14#Xriu!6=rxbq?>MRhBMS$1AASW&+G6S-qYQY2oopdwJR{GhDCPnN zf{l`R9n|!aD5F=v5jf6l9q^!#)yqMnOR1x|H%=Z?8P0Q%!R%1&w^g(6m+NmffL zIVa#Lnq=*Lzn839n`@6G2Adqht>1Ww?CnZOco#*8|951p9o`Q?T1da^(y(@mIv@W} zAuz#GeM+Tr2yZW9IsXpj3$}cXTw_Ewo|sF;0itx6$^1SXS{A9H!6xVREc@-iXY;I6 z>0S{!QdD(i~f6%W8Skj2JLW!&U_d9(>XUp5R-{req^v_lb6C6NO7|5@F{c!>( zQFThGGSaDRZ>Y|3`;=wwZmvA%7e^6u=Eq#?n3ey|R}l4<9AyIuda8i*1}*@nH>T(7 zlzDD$1FG14efJ~2^AO@Hl&_V~-bK)C9dK!uyq;3{yyo-qO=cIkp{V55!3fj2Eznc5 z-x96f&%F0{D$nrsrb$T4Jb3Ya^iM!0v)Qn$jlN5SlhY*$e$T)sN_(xtRw;s5h5hM; zKcs=hz;GZgiWOJvdg1i>H*IsXC(3$I45-aAcVRaX>&Zw<64Ul9Xm(qQRk?^WdI%haDE)M@DeYYclW79kP z=-01nc%F|YcD@nYiNKptb%6usAPwe{d=?O46%Kd?HdQoNH+Lrs`{@sUyO(*)OGFq8 znLfLpApS++g?eXPKA*tBmxf#yW8^yk8Pft9rSdXxM~^}dC>Td(EgLD;&z8zCR_Luy zsXOCme?ADEWWGN30 zfsxyij8LN#!Oj_;LIf6C_uG~h^-KMD$Og(+Bpz-c=l1eLy(H9LHVUN5+qbMd_u^4m z#KG+rEe;ieu6>JFb`{-AQeG`NWp@1`*C;Q5+S*k>L=hhs(O2$ zh<&&aCRX?yYE|=TBA@5J7H01yso_*kmrAE0JwLd1x#saIkaoy?=-AH=RZ}v1+Y&7kklQpyUYgf&0nmWsN&U)nbG>pJ`-g9(sreTQK+m5e^~* z+<-O@WTgRxWjAD?(U6cl?i});mBxz*;?)YGFp6B;(b-adcx%GMx{6JSsNPlhNz4xC z)l95A0z8YhLr<*XZ_TU%+mG2#_}aN13mm_jySzTwn6Bn!%5ii@y#s0sLo0WhGEZLe z_Ez66Df|X2%=p`536bL98GpS$U;qwEd!fz`)5+qRUhBX<&BBp0l1=GMLxo z?9v5$?LF5pv3xKo2TDF0Bj3D!zWSoA%0qVgf!gEStYPB3QJ!f<1 z;Ao2WxvyZNkV{MOOYs3>?3e)$xQyVA_#B8IyZ!R+1wC}?gtGiVfYpnNc}p@mP0Rga zz)!aD4Oo)_*kHO8IZnTEVR8Vu6pfgGtOza#EjQ?^Jjtx@ssQthS!Z!PG@qvsUP=6x z(P@izij^sF0D-Krj^a+-ajUw;oF2VDACS6!oDLwwUmD0gN5&hF^VRus2=1oy+bv&p zURdor=S6}XG8GU@%OsE{y?mt2fy=3MpyWRcnkKG(Qv_`Nu>Ua3P{*UziOgmsOgzf! zo0brLP1b4Nxy<-m*tx!yNP#~kxZJGtO4*C1_YXyr`vo5pf)OD9z|Fa>@a0JvrrY>- z+K~_O@w)U#CjcCXOc~0QPW*EbonHo8-vFHw-;$HiN6L{RgWgOoWfDv&ZgOYldyOQA zC?1I&Nl`Z{{;3oT6&--xqBl$BeJtPCrFw^RBJ%oUu}V(edmBy_;$NtfI^Xkb{*t(y zi6yOd?tc{U1&oD7faa~)8uY2vS5ciVSh)(oeJHBB)k-r_|0tHq|BA-U} z93+8e8EV(yR_^pHoxXSshH5nmnT~!t|DIM}{`uzwkF1|B>Wq48;^Q5a<2iPKT_sV_@yv>N2Q!hASu!J! zc4wJJHaft=21 zU$B{wfFGby8WB=|X(>l%FeaP&FcbBf#BZj`A{UiP+u8~1XHpiGi;@a&(N8@5Q>qgQ zJjdp*hx8=;VjSY zQ|N1Ty!)_y$R3OXVvAN=eU3_Po|({5oJcPqKmwS7WK^Hx5F)Cgx%q@{CepcYe=qaa z7Q1Ve}9 zpPFI`uSJ1${@-HS?>!1zh@U^P$k922xo%I;8%%_azF@I|3V|9285>2?w_C_k#3V=~ zc{zSKo0Wa}$hFBwKLam}N&NTkRemgG)&+rV>))f)nuNNnX44y6Na3dQPDb_&7Plxu zHBzJ3R#08AlOYaf+Py!S@)KeZeg_MbWjaU?aShsU5;V$J)by1=VgPMEw~ChWoI|*# z7^Q~;d2#3oas=D#IhR>pt=D|N+*C22v(n&yGo6ctxq(cE^4Mo8ixEr6!g5M{Fo5f< z7!ZOJZB(-eGa(5WyF~1rV}xiSn-X!K^#oRD!tX1a- zLlGRaM4P-|X5-I$eIcAEVmkHKg$5qTYx1;O=U;GH8Y?W#qX_}z7Q+awGfMntj9nsVABwa!4s0(-4eb_7jcFOe*j`Muo6^!_fqa6tMt5RO$e$YJA(6B!#u zpX4s3Y3{m=R^d)lLF17pWnX9$DxGy8w$I*Q{seZA3bwk*GTP~qzNF4kJIXHVEt|K^ zl=5tJ^@Y(U-sWUbfdM7o=#q}rirvd%!!Aw_oqPljI{C8&cotZWu9lbE{I6YX=}QU% zeuSY((PZ{Y550`j*S~uL={;MtV-n3GMjWGxO)whd@$%BGvgA}vjAxQ0x%jQMPsnk_!_v{c{1 z!ig3fT(Qn>yo?)8MM5;sKdl!&Lw3k;VZd@U__V>t>ywb`4h@O^lQkAHt%0fN_Bd zc^;sQbU<71dmLYA=gluup0oW8oF1t@v_EBekwFU-Y(PfkiNj9rjas)!v zu2CG8(I=^a^2M*#>!MP?+GMxtlU4HW+R`+tNLB!sUdfoGX1wT~@AW$}Y&Ln+UIfAm z2SCXteRJ%kk53@r3BsV&{&XC<>2E|nj}@uPxSxafh25R7KVvem)F z&7)hO#vFsmJ{Uw!D|8IhAmR1R)5fkP1SA{U-5JXeBp45_TFw@1Xp){tnD# zy4g=Z+pua_Mq`Qm#O%`Se6;%-&_E-5wL)7oeZAyqa;vq@mBN#<4q$h zQaS>7IjYDn8L{UD52ZNeM6290y*W6C4@!)Hj$m?7$#V0lr#4wRgWul5bAfgw_7rGT zp?r1nMGK?K_Q)X=ht-l@#Y|B2D_zEZ3$8Yv5Y%m5Nrm1bt8V~w23^Jog>v066nAl> zcf)$%JJW~LV}c{g({~|1)N^yfM{8296j)0pmYI^|npiVwtb)?OoVnzGer!ka+;~m}9#Rw}r*LxIiN82|hQKn9}|Pr1!1@H{Yy< zZ-8>+LXO~DEyiG`+a~|Ji7b${E$?KRO_sPn-!P|TZG3-%GKJ=jVcc6VoMR!=jEx#Y zcXj=d4DrliNHR1^|3hF2d94R1i6f=Prv*DMejg(( zAspW7jtiWgufr+qc$0MpoUX_&$A5*^$*&+;ha9ysfb3(SPNg>oW536Cx?X)ox$aT= zGNp@S%$E_IM24~e2NvEB5STp*3ipJqgNu#IOzjJ!M6c?efzL2^TSb;a9!o~8!J(s12oN2+Ssj3Tj%+dU#HLlL!fY%h7e&?Fc z=*=6ppBpSTRcokR7lEpFQb0pJ%ke{MbbfayZ-T#qtngqh-t2$jNa>v=oaF8ASX(GC zw*t5cH4z2+oxkl%+-rhntKVZu0x_OmtY7AYzn#YD)K zD}sH7s;>R4XlKwq>-@5ybJ&T@lcdNskO8~?s1fH+>TFYJvfwh6eD_Y$Z#iqnTz)F8 zJ+$_gIqCi(lS=PM0-d`43Fa|Z)cp&YDnP$Wj<~wa2{sfg*Kdn_kBrlG@Pm8U+e`4I z0C~875Lc}2vnj=G?M!URr^CPs0!x^AG`dbjGe}c_B2&yqM>}>%ZXw1Zow8e}?a_SI z4(xb1x9DsHM}&b_45ln@2l(U3{c~OQU&}vW!hlZHYr?n8k8y28SAIxnWi*BPAEeV# zN3QOcn*ybW-XoUUth(CeKAv8 z^b+Bn%M9*w9DRuA(0ZiVo%!1$AmBi}Xw*KbUu)z_4xyzMVSAW(K6tp<-D)&)`cfmV zD#id!@$LL0zEQp#>43+*LhQ)-C4QJY7G!Koq3_D9i%ogl_K8aW*i(BpsKL(aTgcKQ zk8^^x?xs*!oPsG*HeDGnQwK9Z;A|+@$#ct4enuf+6RyUm>EV$AHrc`U zeMW}B33AkOV!_7Zl183KujnUubA8apI!h$(20iS&9!UD*Da=L>hZ3WLcHuYW$$b6f)H?p zm2I~*LQyANkNQg9a56mFt!_C|u%%x5xv`426~vW#Vzg)%IS>L15H};oxn7#!A_ONQ zky7xb3^F)}IowobOKyZlAlBjQ58Hf-+=0jWq?D0**VErtJ;KS&UZ7h9?v17Kqw2Nu zbzxhZz0+wWA)5C&EWR0wp5?{G94%9VR%Uuf*k9r=O+cqF3K`A7wf4q>4riKpKVx>A zok1h47P@Cr#!WoU&0{>kJlqK-$^)r*GZ2j$Ey|fR|0`%>^{XFZ3d_)j1XA1~>XBFP zxt_&c6`Y^AFkQ}%I6(b9vIrGXW*I}OL?fYrV-)mAW+LW{`!4sK z55C2IlcLQq3}U5Hm;+e(^6JF_dVXunBC!zT%f;wtg@zs-RO6}Zjpf9pC1Ot`ZeGk$ zTR}V(r;90CzmDop*6p3Qq5A<7j5UkC=W7j+>vY~Yu-iHD>QR}Upup{!C>$c^lxjit zsdCP4EZ4V)Wm|yHItl9>-s{aJ7LrLksrT*PZz>^iE_tZy`&=5xZys+xp;@4fQ-31u z3U(}wJCU=@b~$CXS-r;4sz44Df`sVGsBfm7%!s|05g9{V&i7@|<6`{_ zxm@%*;TD)tu= zqPbM8Zz3!ht#|*(oh???u?lO^fh1;}9ED+Bh9--75S@mmE}u*POzW1cvvXGJA4y%Y zniO(#yLj(2*Hf!M8xTTZ+Zz2~G|cT$*xKw81VzZdm7)W1y>m_(JY`d-1DVuN92Q6Ib?{%?O4PmIQ`m3q+*X8bVfoyJ1f+j5$BtEn;~n&6 z6N?y_lpE$@$r0Q$%>-SK`o4GL{M&k!VuW+LCg6oZ0%na#?p^PPk~}&y{RnYO4r!_A z{!wU2t@2~gj&%M6MNY-Mh={Ml4&Ugra~e2!RDvxop%7pc*a9y^_TF6oG_P2#OuoM% z>ef+h7+0Ka{^rPNmHatSgxC}%8h~;~U6i{65|$O<(I}kU&fbg7zkHs}1$q@;D3ob8 zC2jQARUm5r*&8=DVT*rb?a7 zVyH|)rKS0IO9!(VKg+vGqg<=L(BF>^Tftpwc~T@O`H={3e|#4aBFO?N!BIh@Lm|BN z!<QE$8ktue7w;bI!908l_<7{#S900n#p;61eWGg!L4yyg`x6pptvnB^W<`!Z%D zaZX>RHV^}qzwv(n6QhYa++e=2My39W?MdS{=-2bi(p(4m)}9XcDkC`6W(2 zz9*6zatK4y=fsc>OjmEy)@3M~PH5R)w^Azuw@l=tuXtF(^oa@O`FlBR!BD`44#PSE zz)yfmlrcs!aB3jM+_#l686t(iY*$H|Ho}Nz=U$Cw<~}Rx}M2331TOb zI)zog&#Z$c5;IZ;nAeymC3s#c0HJFVU3ja1OFeqG!U!QaT+tm94t#Q~P{{?wv+t=n-K`tG&@h3_p&Hv+8{qvF-1byvn38cbz z%C&LD)cWImaaH!Tp(#|-#7!bDwLrApJh7Ht$@mXK<%5Ie@Kj2O|Bq?@KfgRRh6e6% zA15VOY5@?plN!*f54qzmip53G@yi#d_JuhbNgY<9E|Lv#$6}tcNUpNt9 z5afRTx!w(yZg@l zI$nrvu?N9xj4T09aOGCH>2)#tf8H-*r&kA~$!{HgrFE}rGHqa%&Vy88X#ZIY|6d=+ z0zM38Y{ns(k9&RM`~OM2kru7yCedgBrr`&7^{W5XAfQQKCyzvBTNBM|fVcpI7|T_w zlmEAs`Tu@3qas2mV&)`({7+dRn2u8kD06xe|APG6AWr*8PoJMW&TnoSy1E7ig1Uo{ z?a&C--rB9SW`Fyq!wJ+@XywSRXB#j-qCmbm5+ONJ4twqZ z##-w%kC4ju!eAf;kJ{S+ule>ro*9S-bbGo^y6kiM9kn+~alO0gr5%BwO}$L*U)z*# zW#o5oaQ8idbG6TFl*a)Da(pJ5WRXrW=vR}Fw~B-psA!mUG6pc4$F^uK*`X?MuIx~D znS!~J15u|O60!+?IfXKtzmLAnHUdoB>47LBYU5fN$DQXrPvutsm80!qxxfou(W^hmN|@AkI^I=c!NO$PfG+%*=X{%dVnTsEdCf_O)>v2hl3V<>tXOAi<_+VScaeZk6A=2lBW*Vt{F=ZV`3kH9pFb5L{t&7p zu56Jfb$8u;Q}OFxwpCYsorYFLC1NC}@V>})P_I?R?qTtq9C9k%UMc;ku^!TwspCIL zZoD&qP_(_n>H3}n5HX{O(uSGuC{L*r6ig#(;7~lMK;6{aNdRET`Z9fk1Fd)n7GIt} zzvqM;j_l4$l0p^B-Sk`y)|qJ#>}3|-friS@pW9S`OWJky`6DwvOd)xd?8dS0bdOmu#NI|T-z7r_+^3^`KuOlk3`#@r9f44^njU0 zG{f>);jkN;@)CB}OOL{o6Xk*pC{!p@<6BVubbgj1C=Xo5nC`F7p)(aYkz8qI0-Q+uuW~a_L~HweDDnBd&X&fzws_*ubaK2`;_;0%NKAS}EvxmNB+P>1 zEix20tL>6$#`VMgs?yH*5!9FkW7l}P_iUL55#bS?a6s?PiC`AcPIsnEr@?I{U-mht zHw5j>(d9W?5D}9Bq9y7_d|$4lvVYYf*Xk_{deSAQXQxXaPCqW7HYIt8qHPZ>E&pQ890dNk%ac=OGO5OfuCdfSz5`0qZ=wALV-5vxlDsoMPw|b% z(eaEOB&{ktsBUh-Yyt&p)$k$|Ha{vp)}4A6F=^EU$NI`WfLL<~5Noy~aDV3pBJHd6 z21l~HzzF9-3@wy3_S)H?Tesah+RX*iGmKl$=)6}x#N~cL3I(yBCpvqm`E(G!Zg()t z){=VaK)CDz;W9;~Y>(iZB}`n3DhAjDlDy~~4sb92Of6jfYR1E88K@W>7wX|*v?8bP zvH+O5e_1Rinf|Cr19)`NTK>qWU6BEiQz<1OJPD+~qlU|gTYZ$`Zn<&9)s1GAOuj}o z1rBBCq=6nSoB%qhbkgM?w3k?qY186<^;sD(89_Nr0GO+44WPc8lM!8x6e5NlIyGyWI8p^LrWpg8`C%?>JqeM-NwmxLg{TF(@_5j&fa4=7@ZaugK#bd zJYav~F{|H1qf4?z|C*}k9E-sB7VdUziZc*1fO$?Rq4eJgV+6wEtPK`-?)i@+T1PzWfDqy z?O+~Jo|xxE+_@d?F0DjTh(G_Aryxr38xWL?2oco5$K`xLseTstqDI#wiP*21EHM=D z8>?x4)*wkkYZzJ}8yWQ57|A!Cl1OPl3)7+PwQkVvra(U)j~0!(si9{|0nt~2ng39Q`wzQ=YczN-> zHOjuQ8vj)OK&G{*VL{RBMJ*C1b@_O%$0Oj*+}7wEH9$d|8f5d~QGrZd@`q5;YeHkR z@7%nK^UC&12L~?^iP98`bn3k>Nem7&nIfHTuYdAsWK-wQ0UEQ~0~L*j42Ns%&TPJ= z4&LQY9ic4jUqo^6>YQ*_uJAZiU!Fx>?;{C(vWa}Yp1?LyLZi^Ul)K9}yG&H~xHPPq z7cN#PVgso%MuGI#C@XX)Bi`{ZOyIXFMI#*U6Krta7Kke19g{HBPfzeRbLOaG*<~js zZILKRb$c}O`d_9PVx{2+np$a{(Ps4byJ{0nZL-}K%V++^V^Mt*A-XTrIYlEo=PmYX z$t;$LI7x>Z3+MiXBBmfru#XB*&>Thp(}mSJD;j=&pIA-`&5DJ%N<;HsRnQ$`i~Gow z_#_4s`(nx)1JyFQ4CqisZ{GrG`HvP$5u#VnJ~)(^#fYgG+-?aCIBCf-+Ue(NHrT1= z{jH+@ypgvR%f{`6G2Y%|Lh84B)$?$9_^5S%yZ)}ve0-dAAnXLS+%7}FXq;TJ2DwRd zw8@m>+~_E)V$FNL9h%QujA*qZ7og`=*AFnu-DYqDYKRS-s4#Te$asy(MXU)oFL18G z$UP>SBVE?$#uYll&${=@0Yw7nB-)cHsBgS0PFC|1Im@R~2coEDy2W%C$z}Wka*`oL z$(klhf>OPf%%3_)r(#(t-FS`7M!N^zZLA3RNJJ^(_fhwaMu&J=^4iX{Xg+WGT=1O8 zHcG|J^UI3}45_Hx4vsJSNu*njz!qSD0QGig%AoO2*v;#nmIm~Ucs%BUE7%tRgN551 z`o|5dTQbC$ae?X4OX!W`clV4}$kK$>y@X9z05cpe2YFO?7|_*m6-@oi&%)kgsXjaT zo6x>Q;*#OQEjTX7;={^VVX%GF$qGY1O9&joSm*gmiBy?2u*E za2%~$Y%{YTQ5&Ktxsp4MNExv^i406LDE9Cs?4Gkl4wykZ=HZHJr~AhQ1#W|B1~qpy z68p8DAHT8r@Q8v!&LYmmee4O*!J~`?Wxu~yKTrSAv@bH?Y;H1QH?vtypZ-&H;8e#_ z1!RpTkb~^V8Mo~K2k!D)VpOx);+Z4{gQj7|e+o1`L0HNR1fnU#KkI%#3$x|Q6AmZ$ zyN}n*6;m>A(w0bFOsrKh>ozYDU0F`l1Jb;{qRpuF<9 zb)xjqM%m2_eNei2pCyF6Im{;0DJ$HRr;?I?0al7PJl%{e^kFre^Db|`=%7MQ$Sw9i zp;P-k*%7Td->t|t->qTv88zn1f#Ow|$KH6DcTDcIgzutNCtH2$bOAwY8# z+aFSKWD3}=cx462;dN#78hdr;w9@+ZeOW?YOJO(rAcL|xP@vz$7w-Qs3j2{vp*9$u z{Aa#E?E&C6DaU<7D--)SXqqe>GV2vHa((&O-=pbiorQ#r)yT-@qVc_}_+VleBDyp1 zXPNTtr7sfLO)fjlABzwzgBJwe`zhAoVW8jcEjgjzHj~0-^JJ#|turV7yM6W?s+bRI zU%fZwu!#<>6i>+Tv9h&ug)WLBw05}g`xTyv%Kg^fLGF!+AeRz@)A#~_+E&Ye!JkF>$aRs zKst6j%e!5mG7K!p$TDwSp5NByLkw5slA>wvEI4~83?4mb*O7k~Tan9L$s6@J(I}CC zQc!@ZfMvS}MZMlDOj!)Tl(6wM`(Yw$05RR^^9Ggs*RPrK9aX`pfO(XRc72XKK9s3n z(cjBECxFR1#+Ewxo#p(RNTCW_YfI|*XjvRkO-u*l#Blg2ve_cgc|8?450%uJAx`tY zBzoF60#2&nU%$_mN{5`B`^5+~3~!-j)JpR(eX?|Pnri@M5y4;SS8`Xm0XEN-8t+mOGONZOjEdhE?G}O&8m#f|HR8^x~4atQPOZy{ons z?Z{fe-?`XU(^FH~Pqj>GTgMl8gUa!HG;>5FCQxje$KdESRDrA$q+wcx*9#Wlv@4I>c(X~VF>ga_^e+9}Z zJVKK1rJ9UEKgHpSa1<^N+oAGz6V4`@*zsM{%e*DmP1UceCX)wFsWeCrl^t8AsV zi4W)r%&L?#*MhPiZgW)W>MI+4?}TugZ}D#u-+?7CxxSyA%DcCO?Mj9HxIHdyqr~RU zO9UrxPDQ)72f%Q8K&k2oM*N+~t=e5FG&jesJ*Dg7`*=?^5-c%aY|61XMo&ENt>c-H zdh~N<6W`0a2lH|Ys}0}mE=7SW582tZty1>wQASvRtn+GKwzcwf#w=s}Pw(QCas66# zu1ARv#?N8;OnxGmNihENEdX;82UVX}kv}hzHR_D6&1ZNNGdTCc-f5@mhbNku?^pcZ zW9jG1{#0i%9>u6nUkQ5T5}!6*V$nPu+&-b7^m_WMS={s*BK-MjZ0(fn=oh6x-W z8*XnYwOso6yuZn0Yj}?Gk9VU%<*Rq&aRXgvZBN7AyyGZ`-rjAAw@+rl@0aD6SXlRV zo3Hl2sv>t<@1xtCFMR19eyMu5oH+#GIQC;m;M4te^Z!}tmJgUVwz@_~?^>8c3j20( zVivOm6L;);<yFJ>@oW zCr~-y;W912NRg{p3Np*yhIsLp?{pP<$B_-(yS+?&O%q`z;2?~aW85?wCj@g=mmOHH zf7;n=Kp7LZhx6?2jGc4w8BDM!)%%?``hniZqS>9$&jIIoVf36)nTlpxN8w1C*4;-i zhRQ2wun6Zx%@|rd=0I|lHDFRAa zTN^D!Sf3-)3T*mTzzmVww*V%|35+J@ixFZ$M?^XvUR%TGwW7@F=}54<@+Z1AZqZx{ z_q_-Ro`@?4KbM&SO$?mgMmo3$-n76$bpaABkQwZQQ})Bd;~~3m&@uIhF#cNP6?$wr(77%v=0ZhaO@j-b_l8 zFTACoBTh&+SfA$fH}Da3c0NTY96-=V{|V>5kB^%X^E!}Y(7Z92jL~6x0u=NmY0z!^ zVx#@cl8v-196Bs+8Hjtzgsoa)OY^GqyKB!=L&ldTOasZFq4hFOa2fIcp;9XikXk%}o~ARQ@txx)+KC6fj#wwBzaskT`}^X_)TWE8l@0ay*|D36tiNCrB8bl%3N7$7 zmmes;H7EiHN@6Y$kVJgV!bjLwdWE^A0TkV^vV_7N1B$7wu3d$>On&cxJ%3j23z?!=TRrX5AWVaQxqQYuN1*Ww2k1TQedf%QvfkmtykUIgjy)0(?7J}J^qSvJ zO|s%VfNADkRJ*nhsoeaGE=^?N!LO%XolyCiZQ zj}inhB&dTq{dtkNSc{_#e=Rp3!qMc|>SKsZDJHg}+xDJCGL<~JiH^v&|A3Bk`uJ#m zC^uVJ)pnjjbPPIX^>=OtG1L@@UD=oikPa`eb_8L;mPI~_4yZH^D(}uVqFml?DHG}& z_KN-agQ^|xO@Cmuz%lt}cBd3g=M< zg({>=+Slydr`^mXqXo^OcdbQPGS~_ioni_ARo1Bw`oyH zE9FiqFmWyLYKTw>zmxyPskoXQS1O`@giCo12j=IFi?AZezcV2C)w<$szu7Neau&M{ z>l#0dQKVT>Zp%Ke>SsBbWmIc^^j`l)Fzh+cbm(XE??^zR=f&%a%$e=~(S(x8+1%vq zgy0&%Q_~f$QMN%aaB1Ld$ly~-{fB8M3*KI%KSzLjd1U(R5*rFFbeMhWd(2HpkXSO; zaF}jmf6gZIk68Ov>04WaUO432O%y0USj2$p&PU`?K6q59u+L+(LLM|MfZ=FbAak`S z=+o|MZKmVMe4V2kvpk|HB~v`?j11G1e>209xAe^7R=svsoL4aMNdrtQ(^#XDc=w-H%ji>qAYpxFo1z_>LBM)fIg%0rZ~_8DuU3m zK=`Ymy@9_-))nb}Br{wYB`9Xn_;2UqTBmL*$nxf~h}6Q+7-1p=loVW|3WniihlvQV zmunHRl<@toyVwB7nMgG~0v!YA4_`NYhkDUxmV_gUGuiw-D+1uf)=YnXGj#O{9B*#h zEQ0rOb#pJ99M0Oz*I7J8?9UcC=HOM>3KiNW>Z^CbUK&Zm%;*KsnsX+N`@$8lH=)Q9 z1ZoJ(#((ENa+G*%^jfjKFph|vJ6$g)u>Y!12HfLLTQ{46_)KqduC_=Y@g3J*=6Mls zsUjI81(%lf{AKN3WMpH&7*y!==)0NI8w&OfBCUIe_G$PY0{;anqUSuG6=E`Z_83cY_d-2uIldergw5%r&Fae zN+16+h*Wu9{DQa*_R;ao(#GpY8r|S5?tBc=u+}3@b#R_6paH?eqgHV$IIj;4uRh^* zr^Zx7^gxvqxQp6zdt9A;J7-TvouK!=-eW}iI$y9JZ_}F0g}$YCmi{Lq)3IemAZos) zq}KJi2vak__IFRy{&op$3?&S>&Fk4|+XZ)S^T13|ki(n9zPyLUO=XzL{qU%eXmgWQ z{FBs2UMxb)pC=F7`MkTA;V)a2p4zRn`sPUPC|6gqC@fCo)4jv*}H6-mCe<5a_T;fS+?Xy)H zt1Aa;*CkWL+<|mY{>QHt&FXs6bB~d-*Q?)o*ym9S%(n<@!NEbWyLz; zwl!FizvpESvGomZ7zsctSk`l_iiRL z+RP^%@#5uhVzAQSxoB+ zaEzT}yOmng75vt%?WdScqijFX)MUsO?SUN>P{CjnH|v+LK}0TEiRH853H`LX&>BO@ z4GR7=$xVyt=|ua|BPXLShe%qOxR+_}TeKA%(yMP-Qf1f=uCP6MuIZvsOrV79Y|