diff --git a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh
index b17a1589190a5..ba4411b7d5ef4 100755
--- a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh
+++ b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh
@@ -23,6 +23,11 @@ check_for_changed_files "yarn openapi:bundle:entity-analytics" true
echo -e "\n[Security Solution OpenAPI Bundling] Lists API\n"
+echo -e "\n[Security Solution OpenAPI Bundling] Endpoint Management API\n"
+
+(cd x-pack/plugins/security_solution && yarn openapi:bundle:endpoint-management)
+check_for_changed_files "yarn openapi:bundle:endpoint-management" true
+
(cd packages/kbn-securitysolution-lists-common && yarn openapi:bundle)
check_for_changed_files "yarn openapi:bundle" true
diff --git a/config/serverless.es.yml b/config/serverless.es.yml
index 5dd773912c3a0..62e201955d9c8 100644
--- a/config/serverless.es.yml
+++ b/config/serverless.es.yml
@@ -46,7 +46,7 @@ telemetry.labels.serverless: search
# Alerts and LLM config
xpack.actions.enabledActionTypes:
- ['.email', '.index', '.slack', '.jira', '.webhook', '.teams', '.gen-ai', '.bedrock']
+ ['.email', '.index', '.slack', '.jira', '.webhook', '.teams', '.gen-ai', '.bedrock', '.gemini']
# Customize empty page state for analytics apps
no_data_page.analyticsNoDataPageFlavor: 'serverless_search'
diff --git a/packages/kbn-search-connectors/components/scheduling/connector_cron_editor.tsx b/packages/kbn-search-connectors/components/scheduling/connector_cron_editor.tsx
index 629f2b432fd11..d5c8572dfa595 100644
--- a/packages/kbn-search-connectors/components/scheduling/connector_cron_editor.tsx
+++ b/packages/kbn-search-connectors/components/scheduling/connector_cron_editor.tsx
@@ -26,7 +26,7 @@ interface ConnectorCronEditorProps {
export const ConnectorCronEditor: React.FC = ({
dataTelemetryIdPrefix,
disabled = false,
- frequencyBlockList = ['MINUTE'],
+ frequencyBlockList = [],
hasSyncTypeChanges,
onReset,
onSave,
diff --git a/packages/kbn-search-connectors/components/scheduling/full_content.tsx b/packages/kbn-search-connectors/components/scheduling/full_content.tsx
index 3a453605f82e2..76051923ff033 100644
--- a/packages/kbn-search-connectors/components/scheduling/full_content.tsx
+++ b/packages/kbn-search-connectors/components/scheduling/full_content.tsx
@@ -216,9 +216,6 @@ export const ConnectorContentScheduling: React.FC {
setScheduling({
diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_panel_action_menu_items.test.ts b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/add_panel_action_menu_items.test.ts
similarity index 100%
rename from src/plugins/dashboard/public/dashboard_app/top_nav/add_panel_action_menu_items.test.ts
rename to src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/add_panel_action_menu_items.test.ts
diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_panel_action_menu_items.ts b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/add_panel_action_menu_items.ts
similarity index 97%
rename from src/plugins/dashboard/public/dashboard_app/top_nav/add_panel_action_menu_items.ts
rename to src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/add_panel_action_menu_items.ts
index 4e90d94caa388..f13b6128ed405 100644
--- a/src/plugins/dashboard/public/dashboard_app/top_nav/add_panel_action_menu_items.ts
+++ b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/add_panel_action_menu_items.ts
@@ -55,7 +55,7 @@ const onAddPanelActionClick =
export const getAddPanelActionMenuItemsGroup = (
api: PresentationContainer,
actions: Array> | undefined,
- closePopover: () => void
+ onPanelSelected: () => void
) => {
const grouped: Record = {};
@@ -72,7 +72,7 @@ export const getAddPanelActionMenuItemsGroup = (
name: actionName,
icon:
(typeof item.getIconType === 'function' ? item.getIconType(context) : undefined) ?? 'empty',
- onClick: onAddPanelActionClick(item, context, closePopover),
+ onClick: onAddPanelActionClick(item, context, onPanelSelected),
'data-test-subj': `create-action-${actionName}`,
description: item?.getDisplayNameTooltip?.(context),
order: item.order ?? 0,
diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.test.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.test.tsx
new file mode 100644
index 0000000000000..17fa7f23f4adb
--- /dev/null
+++ b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.test.tsx
@@ -0,0 +1,110 @@
+/*
+ * 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 React, { type ComponentProps } from 'react';
+import { render, screen, fireEvent, act } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
+import { DashboardPanelSelectionListFlyout } from './dashboard_panel_selection_flyout';
+import type { GroupedAddPanelActions } from './add_panel_action_menu_items';
+
+const defaultProps: Omit<
+ ComponentProps,
+ 'fetchDashboardPanels'
+> = {
+ close: jest.fn(),
+ paddingSize: 's',
+};
+
+const renderComponent = ({
+ fetchDashboardPanels,
+}: Pick, 'fetchDashboardPanels'>) =>
+ render(
+
+
+
+ );
+
+const panelConfiguration: GroupedAddPanelActions[] = [
+ {
+ id: 'panel1',
+ title: 'App 1',
+ items: [
+ {
+ icon: 'icon1',
+ id: 'mockFactory',
+ name: 'Factory 1',
+ description: 'Factory 1 description',
+ 'data-test-subj': 'createNew-mockFactory',
+ onClick: jest.fn(),
+ order: 0,
+ },
+ ],
+ order: 10,
+ 'data-test-subj': 'dashboardEditorMenu-group1Group',
+ },
+];
+
+describe('DashboardPanelSelectionListFlyout', () => {
+ it('renders a loading indicator when fetchDashboardPanel has not yielded any value', async () => {
+ const promiseDelay = 5000;
+
+ renderComponent({
+ fetchDashboardPanels: jest.fn(
+ () =>
+ new Promise((resolve) => {
+ setTimeout(() => resolve(panelConfiguration), promiseDelay);
+ })
+ ),
+ });
+
+ expect(
+ await screen.findByTestId('dashboardPanelSelectionLoadingIndicator')
+ ).toBeInTheDocument();
+ });
+
+ it('renders an error indicator when fetchDashboardPanel errors', async () => {
+ renderComponent({
+ fetchDashboardPanels: jest.fn().mockRejectedValue(new Error('simulated error')),
+ });
+
+ expect(await screen.findByTestId('dashboardPanelSelectionErrorIndicator')).toBeInTheDocument();
+ });
+
+ it('renders the list of available panels when fetchDashboardPanel resolves a value', async () => {
+ renderComponent({ fetchDashboardPanels: jest.fn().mockResolvedValue(panelConfiguration) });
+
+ expect(await screen.findByTestId(panelConfiguration[0]['data-test-subj']!)).toBeInTheDocument();
+ });
+
+ it('renders a not found message when a user searches for an item that is not in the selection list', async () => {
+ renderComponent({ fetchDashboardPanels: jest.fn().mockResolvedValue(panelConfiguration) });
+
+ expect(await screen.findByTestId(panelConfiguration[0]['data-test-subj']!)).toBeInTheDocument();
+
+ act(() => {
+ userEvent.type(
+ screen.getByTestId('dashboardPanelSelectionFlyout__searchInput'),
+ 'non existent panel'
+ );
+ });
+
+ expect(await screen.findByTestId('dashboardPanelSelectionNoPanelMessage')).toBeInTheDocument();
+ });
+
+ it('invokes the close method when the flyout close btn is clicked', async () => {
+ renderComponent({ fetchDashboardPanels: jest.fn().mockResolvedValue(panelConfiguration) });
+
+ fireEvent.click(await screen.findByTestId('dashboardPanelSelectionCloseBtn'));
+
+ expect(defaultProps.close).toHaveBeenCalled();
+ });
+});
diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.tsx
new file mode 100644
index 0000000000000..bb23fd6798b11
--- /dev/null
+++ b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.tsx
@@ -0,0 +1,287 @@
+/*
+ * 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 React, { useEffect, useState } from 'react';
+import { i18n as i18nFn } from '@kbn/i18n';
+import { type EuiFlyoutProps, EuiLoadingChart } from '@elastic/eui';
+import orderBy from 'lodash/orderBy';
+import {
+ EuiEmptyPrompt,
+ EuiButtonEmpty,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFlyoutBody,
+ EuiFlyoutFooter,
+ EuiFlyoutHeader,
+ EuiForm,
+ EuiBadge,
+ EuiFormRow,
+ EuiTitle,
+ EuiFieldSearch,
+ useEuiTheme,
+ EuiListGroup,
+ EuiListGroupItem,
+ EuiToolTip,
+ EuiText,
+} from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n-react';
+import {
+ type PanelSelectionMenuItem,
+ type GroupedAddPanelActions,
+} from './add_panel_action_menu_items';
+
+export interface DashboardPanelSelectionListFlyoutProps {
+ /** Handler to close flyout */
+ close: () => void;
+ /** Padding for flyout */
+ paddingSize: Exclude;
+ /** Fetches the panels available for a dashboard */
+ fetchDashboardPanels: () => Promise;
+}
+
+export const DashboardPanelSelectionListFlyout: React.FC<
+ DashboardPanelSelectionListFlyoutProps
+> = ({ close, paddingSize, fetchDashboardPanels }) => {
+ const { euiTheme } = useEuiTheme();
+ const [{ data: panels, loading, error }, setPanelState] = useState<{
+ loading: boolean;
+ data: GroupedAddPanelActions[] | null;
+ error: unknown | null;
+ }>({ loading: true, data: null, error: null });
+
+ const [searchTerm, setSearchTerm] = useState('');
+ const [panelsSearchResult, setPanelsSearchResult] = useState(
+ panels
+ );
+
+ useEffect(() => {
+ const requestDashboardPanels = () => {
+ fetchDashboardPanels()
+ .then((_panels) =>
+ setPanelState((prevState) => ({
+ ...prevState,
+ loading: false,
+ data: _panels,
+ }))
+ )
+ .catch((err) =>
+ setPanelState((prevState) => ({
+ ...prevState,
+ loading: false,
+ error: err,
+ }))
+ );
+ };
+
+ requestDashboardPanels();
+ }, [fetchDashboardPanels]);
+
+ useEffect(() => {
+ const _panels = (panels ?? []).slice(0);
+
+ if (!searchTerm) {
+ return setPanelsSearchResult(_panels);
+ }
+
+ const q = searchTerm.toLowerCase();
+
+ setPanelsSearchResult(
+ orderBy(
+ _panels.map((panel) => {
+ const groupSearchMatch = panel.title.toLowerCase().includes(q);
+
+ const [groupSearchMatchAgg, items] = panel.items.reduce(
+ (acc, cur) => {
+ const searchMatch = cur.name.toLowerCase().includes(q);
+
+ acc[0] = acc[0] || searchMatch;
+ acc[1].push({
+ ...cur,
+ isDisabled: !(groupSearchMatch || searchMatch),
+ });
+
+ return acc;
+ },
+ [groupSearchMatch, [] as PanelSelectionMenuItem[]]
+ );
+
+ return {
+ ...panel,
+ isDisabled: !groupSearchMatchAgg,
+ items,
+ };
+ }),
+ ['isDisabled']
+ )
+ );
+ }, [panels, searchTerm]);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setSearchTerm(e.target.value);
+ }}
+ aria-label={i18nFn.translate(
+ 'dashboard.editorMenu.addPanelFlyout.searchLabelText',
+ { defaultMessage: 'search field for panels' }
+ )}
+ className="nsPanelSelectionFlyout__searchInput"
+ data-test-subj="dashboardPanelSelectionFlyout__searchInput"
+ />
+
+
+
+
+ {loading ? (
+ }
+ />
+ ) : (
+
+ {panelsSearchResult?.some(({ isDisabled }) => !isDisabled) ? (
+ panelsSearchResult.map(
+ ({ id, title, items, isDisabled, ['data-test-subj']: dataTestSubj }) =>
+ !isDisabled ? (
+
+
+ {typeof title === 'string' ? {title}
: title}
+
+
+ {items?.map((item, idx) => {
+ return (
+
+ {!item.isDeprecated ? (
+ {item.name}
+ ) : (
+
+
+ {item.name}
+
+
+
+
+
+
+
+ )}
+
+ }
+ onClick={item?.onClick}
+ iconType={item.icon}
+ data-test-subj={item['data-test-subj']}
+ isDisabled={item.isDisabled}
+ />
+ );
+ })}
+
+
+ ) : null
+ )
+ ) : (
+ <>
+ {Boolean(error) ? (
+
+
+
+ }
+ data-test-subj="dashboardPanelSelectionErrorIndicator"
+ />
+ ) : (
+
+
+
+ )}
+ >
+ )}
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/index.ts b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/index.ts
new file mode 100644
index 0000000000000..5b94fba6bfffc
--- /dev/null
+++ b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/index.ts
@@ -0,0 +1,10 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 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 { useGetDashboardPanels } from './use_get_dashboard_panels';
+export { DashboardPanelSelectionListFlyout } from './dashboard_panel_selection_flyout';
diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.test.ts b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.test.ts
new file mode 100644
index 0000000000000..b8ca0cd27aa01
--- /dev/null
+++ b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.test.ts
@@ -0,0 +1,220 @@
+/*
+ * 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 { renderHook } from '@testing-library/react-hooks';
+import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public';
+import type { PresentationContainer } from '@kbn/presentation-containers';
+import type { Action } from '@kbn/ui-actions-plugin/public';
+import { type BaseVisType, VisGroups, VisTypeAlias } from '@kbn/visualizations-plugin/public';
+import { COMMON_EMBEDDABLE_GROUPING } from '@kbn/embeddable-plugin/public';
+import { useGetDashboardPanels } from './use_get_dashboard_panels';
+import { pluginServices } from '../../../services/plugin_services';
+
+const mockApi = { addNewPanel: jest.fn() } as unknown as jest.Mocked;
+
+describe('Get dashboard panels hook', () => {
+ const defaultHookProps: Parameters[0] = {
+ api: mockApi,
+ createNewVisType: jest.fn(),
+ };
+
+ type PluginServices = ReturnType;
+
+ let compatibleTriggerActionsRequestSpy: jest.SpyInstance<
+ ReturnType>
+ >;
+
+ let dashboardVisualizationGroupGetterSpy: jest.SpyInstance<
+ ReturnType
+ >;
+
+ let dashboardVisualizationAliasesGetterSpy: jest.SpyInstance<
+ ReturnType
+ >;
+
+ beforeAll(() => {
+ const _pluginServices = pluginServices.getServices();
+
+ compatibleTriggerActionsRequestSpy = jest.spyOn(
+ _pluginServices.uiActions,
+ 'getTriggerCompatibleActions'
+ );
+
+ dashboardVisualizationGroupGetterSpy = jest.spyOn(_pluginServices.visualizations, 'getByGroup');
+
+ dashboardVisualizationAliasesGetterSpy = jest.spyOn(
+ _pluginServices.visualizations,
+ 'getAliases'
+ );
+ });
+
+ beforeEach(() => {
+ compatibleTriggerActionsRequestSpy.mockResolvedValue([]);
+ dashboardVisualizationGroupGetterSpy.mockReturnValue([]);
+ dashboardVisualizationAliasesGetterSpy.mockReturnValue([]);
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ afterAll(() => {
+ jest.resetAllMocks();
+ });
+
+ describe('useGetDashboardPanels', () => {
+ it('hook return value is callable', () => {
+ const { result } = renderHook(() => useGetDashboardPanels(defaultHookProps));
+ expect(result.current).toBeInstanceOf(Function);
+ });
+
+ it('returns a callable method that yields a cached result if invoked after a prior resolution', async () => {
+ const { result } = renderHook(() => useGetDashboardPanels(defaultHookProps));
+ expect(result.current).toBeInstanceOf(Function);
+
+ const firstInvocationResult = await result.current(jest.fn());
+
+ expect(compatibleTriggerActionsRequestSpy).toHaveBeenCalledWith(ADD_PANEL_TRIGGER, {
+ embeddable: expect.objectContaining(mockApi),
+ });
+
+ const secondInvocationResult = await result.current(jest.fn());
+
+ expect(firstInvocationResult).toStrictEqual(secondInvocationResult);
+
+ expect(compatibleTriggerActionsRequestSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('augmenting ui action group items with dashboard visualization types', () => {
+ it.each([
+ ['visualizations', VisGroups.PROMOTED],
+ [COMMON_EMBEDDABLE_GROUPING.legacy.id, VisGroups.LEGACY],
+ [COMMON_EMBEDDABLE_GROUPING.annotation.id, VisGroups.TOOLS],
+ ])(
+ 'includes in the ui action %s group, %s dashboard visualization group types',
+ async (uiActionGroupId, dashboardVisualizationGroupId) => {
+ const mockVisualizationsUiAction: Action
+ setShowErrors(false)}
+ >
+ {i18n.translate('xpack.enterpriseSearch.indexOverview.indexErrors.hideErrorsLabel', {
+ defaultMessage: 'Hide full error',
+ })}
+
+ >
+ )}
+ {!showErrors && (
+ setShowErrors(true)}
+ >
+ {i18n.translate('xpack.enterpriseSearch.indexOverview.indexErrors.showErrorsLabel', {
+ defaultMessage: 'Show full error',
+ })}
+
+ )}
+
+ ) : null;
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx
index 7c13a3f524ccf..538cc1c575fc9 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx
@@ -40,6 +40,7 @@ import { CrawlerConfiguration } from './crawler/crawler_configuration/crawler_co
import { SearchIndexDomainManagement } from './crawler/domain_management/domain_management';
import { NoConnectorRecord } from './crawler/no_connector_record';
import { SearchIndexDocuments } from './documents';
+import { IndexError } from './index_error';
import { SearchIndexIndexMappings } from './index_mappings';
import { IndexNameLogic } from './index_name_logic';
import { IndexViewLogic } from './index_view_logic';
@@ -239,6 +240,7 @@ export const SearchIndex: React.FC = () => {
rightSideItems: getHeaderActions(index),
}}
>
+
{
@@ -245,7 +245,7 @@ export const SemanticSearchGuide: React.FC = () => {
@@ -293,7 +293,7 @@ export const SemanticSearchGuide: React.FC = () => {
semantic_text }}
/>
diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts
index bc70714b79158..1468d2ac5b11e 100644
--- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts
+++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts
@@ -193,6 +193,10 @@ export interface FleetServerPolicy {
* The coordinator index of the policy
*/
coordinator_idx: number;
+ /**
+ * The namespaces of the policy
+ */
+ namespaces?: string[];
/**
* The opaque payload.
*/
diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts
index dd63d09c9d7c5..a5dbbc6b233b3 100644
--- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts
+++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts
@@ -1230,6 +1230,7 @@ describe('Agent policy', () => {
mockedGetFullAgentPolicy.mockResolvedValue({
id: 'policy123',
revision: 1,
+ namespaces: ['mySpace'],
inputs: [
{
id: 'input-123',
@@ -1282,10 +1283,16 @@ describe('Agent policy', () => {
}),
expect.objectContaining({
'@timestamp': expect.anything(),
- data: { id: 'policy123', inputs: [{ id: 'input-123' }], revision: 1 },
+ data: {
+ id: 'policy123',
+ inputs: [{ id: 'input-123' }],
+ revision: 1,
+ namespaces: ['mySpace'],
+ },
default_fleet_server: false,
policy_id: 'policy123',
revision_idx: 1,
+ namespaces: ['mySpace'],
}),
],
refresh: 'wait_for',
diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts
index 36a62af378c31..d243ef8b60e16 100644
--- a/x-pack/plugins/fleet/server/services/agent_policy.ts
+++ b/x-pack/plugins/fleet/server/services/agent_policy.ts
@@ -1137,6 +1137,7 @@ class AgentPolicyService {
'@timestamp': new Date().toISOString(),
revision_idx: fullPolicy.revision,
coordinator_idx: 0,
+ namespaces: fullPolicy.namespaces,
data: fullPolicy as unknown as FleetServerPolicy['data'],
policy_id: fullPolicy.id,
default_fleet_server: policy.is_default_fleet_server === true,
diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts
index ba615678c334e..df37dd9707b04 100644
--- a/x-pack/plugins/lens/public/plugin.ts
+++ b/x-pack/plugins/lens/public/plugin.ts
@@ -648,7 +648,13 @@ export class LensPlugin {
);
// Displays the add ESQL panel in the dashboard add Panel menu
- const createESQLPanelAction = new CreateESQLPanelAction(startDependencies, core);
+ const createESQLPanelAction = new CreateESQLPanelAction(startDependencies, core, async () => {
+ if (!this.editorFrameService) {
+ await this.initDependenciesForApi();
+ }
+
+ return this.editorFrameService!;
+ });
startDependencies.uiActions.addTriggerAction(ADD_PANEL_TRIGGER, createESQLPanelAction);
const discoverLocator = startDependencies.share?.url.locators.get('DISCOVER_APP_LOCATOR');
diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action.test.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action.test.tsx
index 97b59a93829e3..63844b1d6d3ea 100644
--- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action.test.tsx
+++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action.test.tsx
@@ -6,9 +6,10 @@
*/
import type { CoreStart } from '@kbn/core/public';
import { coreMock } from '@kbn/core/public/mocks';
+import { getMockPresentationContainer } from '@kbn/presentation-containers/mocks';
import type { LensPluginStartDependencies } from '../../plugin';
+import type { EditorFrameService } from '../../editor_frame_service';
import { createMockStartDependencies } from '../../editor_frame_service/mocks';
-import { getMockPresentationContainer } from '@kbn/presentation-containers/mocks';
import { CreateESQLPanelAction } from './create_action';
describe('create Lens panel action', () => {
@@ -16,9 +17,22 @@ describe('create Lens panel action', () => {
const mockStartDependencies =
createMockStartDependencies() as unknown as LensPluginStartDependencies;
const mockPresentationContainer = getMockPresentationContainer();
+
+ const mockEditorFrameService = {
+ loadVisualizations: jest.fn(),
+ loadDatasources: jest.fn(),
+ } as unknown as EditorFrameService;
+
+ const mockGetEditorFrameService = jest.fn(() => Promise.resolve(mockEditorFrameService));
+
describe('compatibility check', () => {
it('is incompatible if ui setting for ES|QL is off', async () => {
- const configurablePanelAction = new CreateESQLPanelAction(mockStartDependencies, core);
+ const configurablePanelAction = new CreateESQLPanelAction(
+ mockStartDependencies,
+ core,
+ mockGetEditorFrameService
+ );
+
const isCompatible = await configurablePanelAction.isCompatible({
embeddable: mockPresentationContainer,
});
@@ -36,7 +50,13 @@ describe('create Lens panel action', () => {
},
},
} as CoreStart;
- const createESQLAction = new CreateESQLPanelAction(mockStartDependencies, updatedCore);
+
+ const createESQLAction = new CreateESQLPanelAction(
+ mockStartDependencies,
+ updatedCore,
+ mockGetEditorFrameService
+ );
+
const isCompatible = await createESQLAction.isCompatible({
embeddable: mockPresentationContainer,
});
diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action.tsx
index f1d58f9702fb4..6fb9310158082 100644
--- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action.tsx
+++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action.tsx
@@ -11,6 +11,7 @@ import { EmbeddableApiContext } from '@kbn/presentation-publishing';
import { apiIsPresentationContainer } from '@kbn/presentation-containers';
import { COMMON_VISUALIZATION_GROUPING } from '@kbn/visualizations-plugin/public';
import type { LensPluginStartDependencies } from '../../plugin';
+import type { EditorFrameService } from '../../editor_frame_service';
const ACTION_CREATE_ESQL_CHART = 'ACTION_CREATE_ESQL_CHART';
@@ -25,7 +26,8 @@ export class CreateESQLPanelAction implements Action {
constructor(
protected readonly startDependencies: LensPluginStartDependencies,
- protected readonly core: CoreStart
+ protected readonly core: CoreStart,
+ protected readonly getEditorFrameService: () => Promise
) {}
public getDisplayName(): string {
@@ -41,18 +43,21 @@ export class CreateESQLPanelAction implements Action {
public async isCompatible({ embeddable }: EmbeddableApiContext) {
if (!apiIsPresentationContainer(embeddable)) return false;
- // compatible only when ES|QL advanced setting is enabled
const { isCreateActionCompatible } = await getAsyncHelpers();
+
return isCreateActionCompatible(this.core);
}
public async execute({ embeddable }: EmbeddableApiContext) {
if (!apiIsPresentationContainer(embeddable)) throw new IncompatibleActionError();
const { executeCreateAction } = await getAsyncHelpers();
+ const editorFrameService = await this.getEditorFrameService();
+
executeCreateAction({
deps: this.startDependencies,
core: this.core,
api: embeddable,
+ editorFrameService,
});
}
}
diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts
index 65ac6ef69aee8..8768bc721480d 100644
--- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts
+++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts
@@ -21,6 +21,7 @@ import { suggestionsApi } from '../../lens_suggestions_api';
import { generateId } from '../../id_generator';
import { executeEditAction } from './edit_action_helpers';
import { Embeddable } from '../../embeddable';
+import type { EditorFrameService } from '../../editor_frame_service';
// datasourceMap and visualizationMap setters/getters
export const [getVisualizationMap, setVisualizationMap] = createGetterSetter<
@@ -31,7 +32,7 @@ export const [getDatasourceMap, setDatasourceMap] = createGetterSetter<
Record>
>('DatasourceMap', false);
-export function isCreateActionCompatible(core: CoreStart) {
+export async function isCreateActionCompatible(core: CoreStart) {
return core.uiSettings.get(ENABLE_ESQL);
}
@@ -39,13 +40,13 @@ export async function executeCreateAction({
deps,
core,
api,
+ editorFrameService,
}: {
deps: LensPluginStartDependencies;
core: CoreStart;
api: PresentationContainer;
+ editorFrameService: EditorFrameService;
}) {
- const isCompatibleAction = isCreateActionCompatible(core);
-
const getFallbackDataView = async () => {
const indexName = await getIndexForESQLQuery({ dataViews: deps.dataViews });
if (!indexName) return null;
@@ -53,13 +54,33 @@ export async function executeCreateAction({
return dataView;
};
- const dataView = await getFallbackDataView();
+ const [isCompatibleAction, dataView] = await Promise.all([
+ isCreateActionCompatible(core),
+ getFallbackDataView(),
+ ]);
if (!isCompatibleAction || !dataView) {
throw new IncompatibleActionError();
}
- const visualizationMap = getVisualizationMap();
- const datasourceMap = getDatasourceMap();
+
+ let visualizationMap = getVisualizationMap();
+ let datasourceMap = getDatasourceMap();
+
+ if (!visualizationMap || !datasourceMap) {
+ [visualizationMap, datasourceMap] = await Promise.all([
+ editorFrameService.loadVisualizations(),
+ editorFrameService.loadDatasources(),
+ ]);
+
+ if (!visualizationMap && !datasourceMap) {
+ throw new IncompatibleActionError();
+ }
+
+ // persist for retrieval elsewhere
+ setDatasourceMap(datasourceMap);
+ setVisualizationMap(visualizationMap);
+ }
+
const defaultIndex = dataView.getIndexPattern();
const defaultEsqlQuery = {
diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/inference_models.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/inference_models.ts
index 2895d1fed4336..736f4f275bb36 100644
--- a/x-pack/plugins/ml/public/application/services/ml_api_service/inference_models.ts
+++ b/x-pack/plugins/ml/public/application/services/ml_api_service/inference_models.ts
@@ -31,5 +31,18 @@ export function inferenceModelsApiProvider(httpService: HttpService) {
});
return result;
},
+ /**
+ * Gets all inference endpoints
+ */
+ async getAllInferenceEndpoints() {
+ const result = await httpService.http<{
+ endpoints: estypes.InferenceModelConfigContainer[];
+ }>({
+ path: `${ML_INTERNAL_BASE_PATH}/_inference/all`,
+ method: 'GET',
+ version: '1',
+ });
+ return result;
+ },
};
}
diff --git a/x-pack/plugins/ml/server/routes/inference_models.ts b/x-pack/plugins/ml/server/routes/inference_models.ts
index 29f687ede932d..cb12d87e2b6fc 100644
--- a/x-pack/plugins/ml/server/routes/inference_models.ts
+++ b/x-pack/plugins/ml/server/routes/inference_models.ts
@@ -7,6 +7,7 @@
import type { CloudSetup } from '@kbn/cloud-plugin/server';
import { schema } from '@kbn/config-schema';
import type { InferenceModelConfig, InferenceTaskType } from '@elastic/elasticsearch/lib/api/types';
+import type { InferenceAPIConfigResponse } from '@kbn/ml-trained-models-utils';
import type { RouteInitialization } from '../types';
import { createInferenceSchema } from './schemas/inference_schema';
import { modelsProvider } from '../models/model_management';
@@ -63,4 +64,40 @@ export function inferenceModelRoutes(
}
)
);
+ /**
+ * @apiGroup TrainedModels
+ *
+ * @api {put} /internal/ml/_inference/:taskType/:inferenceId Create Inference Endpoint
+ * @apiName CreateInferenceEndpoint
+ * @apiDescription Create Inference Endpoint
+ */
+ router.versioned
+ .get({
+ path: `${ML_INTERNAL_BASE_PATH}/_inference/all`,
+ access: 'internal',
+ options: {
+ tags: ['access:ml:canGetTrainedModels'],
+ },
+ })
+ .addVersion(
+ {
+ version: '1',
+ validate: {},
+ },
+ routeGuard.fullLicenseAPIGuard(async ({ client, response }) => {
+ try {
+ const body = await client.asCurrentUser.transport.request<{
+ models: InferenceAPIConfigResponse[];
+ }>({
+ method: 'GET',
+ path: `/_inference/_all`,
+ });
+ return response.ok({
+ body,
+ });
+ } catch (e) {
+ return response.customError(wrapError(e));
+ }
+ })
+ );
}
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/delete_ingest_pipeline.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/delete_ingest_pipeline.ts
index c1516e342ac1d..f4c46d8447d8f 100644
--- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/delete_ingest_pipeline.ts
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/delete_ingest_pipeline.ts
@@ -24,7 +24,7 @@ export async function deleteHistoryIngestPipeline(
esClient.ingest.deletePipeline({ id: historyPipelineId }, { ignore: [404] })
);
} catch (e) {
- logger.error(`Unable to delete history ingest pipeline [${definition.id}].`);
+ logger.error(`Unable to delete history ingest pipeline [${definition.id}]: ${e}`);
throw e;
}
}
@@ -40,7 +40,7 @@ export async function deleteLatestIngestPipeline(
esClient.ingest.deletePipeline({ id: latestPipelineId }, { ignore: [404] })
);
} catch (e) {
- logger.error(`Unable to delete latest ingest pipeline [${definition.id}].`);
+ logger.error(`Unable to delete latest ingest pipeline [${definition.id}]: ${e}`);
throw e;
}
}
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/entity_definition_with_backfill.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/entity_definition_with_backfill.ts
index 6d4026973ca38..66a79825fbfb0 100644
--- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/entity_definition_with_backfill.ts
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/entity_definition_with_backfill.ts
@@ -7,7 +7,7 @@
import { entityDefinitionSchema } from '@kbn/entities-schema';
export const entityDefinitionWithBackfill = entityDefinitionSchema.parse({
- id: 'admin-console-services',
+ id: 'admin-console-services-backfill',
version: '999.999.999',
name: 'Services for Admin Console',
type: 'service',
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/index.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/index.ts
new file mode 100644
index 0000000000000..eae0e8e8afc9a
--- /dev/null
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/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; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+export { entityDefinition } from './entity_definition';
+export { entityDefinitionWithBackfill } from './entity_definition_with_backfill';
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/install_entity_definition.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/install_entity_definition.ts
index 875242f73d751..a58019bf236ae 100644
--- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/install_entity_definition.ts
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/install_entity_definition.ts
@@ -36,8 +36,8 @@ import {
import { uninstallEntityDefinition } from './uninstall_entity_definition';
import { isBackfillEnabled } from './helpers/is_backfill_enabled';
import { deleteTemplate, upsertTemplate } from '../manage_index_templates';
-import { getEntitiesLatestIndexTemplateConfig } from '../../templates/entities_latest_template';
-import { getEntitiesHistoryIndexTemplateConfig } from '../../templates/entities_history_template';
+import { getEntitiesLatestIndexTemplateConfig } from './templates/entities_latest_template';
+import { getEntitiesHistoryIndexTemplateConfig } from './templates/entities_history_template';
export interface InstallDefinitionParams {
esClient: ElasticsearchClient;
@@ -111,7 +111,7 @@ export async function installEntityDefinition({
return entityDefinition;
} catch (e) {
- logger.error(`Failed to install entity definition ${definition.id}`, e);
+ logger.error(`Failed to install entity definition ${definition.id}: ${e}`);
// Clean up anything that was successful.
if (installState.definition) {
await deleteEntityDefinition(soClient, definition, logger);
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/read_entity_definition.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/read_entity_definition.ts
index 91194140101b7..37a0a48b92b5a 100644
--- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/read_entity_definition.ts
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/read_entity_definition.ts
@@ -30,7 +30,7 @@ export async function readEntityDefinition(
try {
return entityDefinitionSchema.parse(response.saved_objects[0].attributes);
} catch (e) {
- logger.error(`Unable to parse entity definition with [${id}]`);
+ logger.error(`Unable to parse entity definition with [${id}]: ${e}`);
throw e;
}
}
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_and_delete_transform.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_and_delete_transform.ts
index d49165be22106..17ffeb44affc1 100644
--- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_and_delete_transform.ts
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/stop_and_delete_transform.ts
@@ -38,7 +38,7 @@ export async function stopAndDeleteHistoryTransform(
{ logger }
);
} catch (e) {
- logger.error(`Cannot stop or delete history transform [${definition.id}]`);
+ logger.error(`Cannot stop or delete history transform [${definition.id}]: ${e}`);
throw e;
}
}
@@ -67,7 +67,7 @@ export async function stopAndDeleteHistoryBackfillTransform(
{ logger }
);
} catch (e) {
- logger.error(`Cannot stop or delete history backfill transform [${definition.id}]`);
+ logger.error(`Cannot stop or delete history backfill transform [${definition.id}]: ${e}`);
throw e;
}
}
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/__snapshots__/entities_history_template.test.ts.snap b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/__snapshots__/entities_history_template.test.ts.snap
new file mode 100644
index 0000000000000..94af9f3307f04
--- /dev/null
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/__snapshots__/entities_history_template.test.ts.snap
@@ -0,0 +1,78 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`getEntitiesHistoryIndexTemplateConfig(definitionId) should generate a valid index template 1`] = `
+Object {
+ "_meta": Object {
+ "description": "Index template for indices managed by the Elastic Entity Model's entity discovery framework for the history dataset",
+ "ecs_version": "8.0.0",
+ "managed": true,
+ "managed_by": "elastic_entity_model",
+ },
+ "composed_of": Array [
+ "entities_v1_history_base",
+ "entities_v1_entity",
+ "entities_v1_event",
+ "admin-console-services@platform",
+ "admin-console-services-history@platform",
+ "admin-console-services@custom",
+ "admin-console-services-history@custom",
+ ],
+ "ignore_missing_component_templates": Array [
+ "admin-console-services@platform",
+ "admin-console-services-history@platform",
+ "admin-console-services@custom",
+ "admin-console-services-history@custom",
+ ],
+ "index_patterns": Array [
+ ".entities.v1.history.admin-console-services.*",
+ ],
+ "name": "entities_v1_history_admin-console-services_index_template",
+ "priority": 200,
+ "template": Object {
+ "mappings": Object {
+ "_meta": Object {
+ "version": "1.6.0",
+ },
+ "date_detection": false,
+ "dynamic_templates": Array [
+ Object {
+ "strings_as_keyword": Object {
+ "mapping": Object {
+ "fields": Object {
+ "text": Object {
+ "type": "text",
+ },
+ },
+ "ignore_above": 1024,
+ "type": "keyword",
+ },
+ "match_mapping_type": "string",
+ },
+ },
+ Object {
+ "entity_metrics": Object {
+ "mapping": Object {
+ "type": "{dynamic_type}",
+ },
+ "match_mapping_type": Array [
+ "long",
+ "double",
+ ],
+ "path_match": "entity.metrics.*",
+ },
+ },
+ ],
+ },
+ "settings": Object {
+ "index": Object {
+ "codec": "best_compression",
+ "mapping": Object {
+ "total_fields": Object {
+ "limit": 2000,
+ },
+ },
+ },
+ },
+ },
+}
+`;
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/__snapshots__/entities_latest_template.test.ts.snap b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/__snapshots__/entities_latest_template.test.ts.snap
new file mode 100644
index 0000000000000..b4247098d9498
--- /dev/null
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/__snapshots__/entities_latest_template.test.ts.snap
@@ -0,0 +1,78 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`getEntitiesLatestIndexTemplateConfig(definitionId) should generate a valid index template 1`] = `
+Object {
+ "_meta": Object {
+ "description": "Index template for indices managed by the Elastic Entity Model's entity discovery framework for the latest dataset",
+ "ecs_version": "8.0.0",
+ "managed": true,
+ "managed_by": "elastic_entity_model",
+ },
+ "composed_of": Array [
+ "entities_v1_latest_base",
+ "entities_v1_entity",
+ "entities_v1_event",
+ "admin-console-services@platform",
+ "admin-console-services-latest@platform",
+ "admin-console-services@custom",
+ "admin-console-services-latest@custom",
+ ],
+ "ignore_missing_component_templates": Array [
+ "admin-console-services@platform",
+ "admin-console-services-latest@platform",
+ "admin-console-services@custom",
+ "admin-console-services-latest@custom",
+ ],
+ "index_patterns": Array [
+ ".entities.v1.latest.admin-console-services",
+ ],
+ "name": "entities_v1_latest_admin-console-services_index_template",
+ "priority": 200,
+ "template": Object {
+ "mappings": Object {
+ "_meta": Object {
+ "version": "1.6.0",
+ },
+ "date_detection": false,
+ "dynamic_templates": Array [
+ Object {
+ "strings_as_keyword": Object {
+ "mapping": Object {
+ "fields": Object {
+ "text": Object {
+ "type": "text",
+ },
+ },
+ "ignore_above": 1024,
+ "type": "keyword",
+ },
+ "match_mapping_type": "string",
+ },
+ },
+ Object {
+ "entity_metrics": Object {
+ "mapping": Object {
+ "type": "{dynamic_type}",
+ },
+ "match_mapping_type": Array [
+ "long",
+ "double",
+ ],
+ "path_match": "entity.metrics.*",
+ },
+ },
+ ],
+ },
+ "settings": Object {
+ "index": Object {
+ "codec": "best_compression",
+ "mapping": Object {
+ "total_fields": Object {
+ "limit": 2000,
+ },
+ },
+ },
+ },
+ },
+}
+`;
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_history_template.test.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_history_template.test.ts
new file mode 100644
index 0000000000000..11aad78741020
--- /dev/null
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_history_template.test.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.
+ */
+
+import { entityDefinition } from '../helpers/fixtures/entity_definition';
+import { getEntitiesHistoryIndexTemplateConfig } from './entities_history_template';
+
+describe('getEntitiesHistoryIndexTemplateConfig(definitionId)', () => {
+ it('should generate a valid index template', () => {
+ const template = getEntitiesHistoryIndexTemplateConfig(entityDefinition.id);
+ expect(template).toMatchSnapshot();
+ });
+});
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/templates/entities_history_template.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_history_template.ts
similarity index 87%
rename from x-pack/plugins/observability_solution/entity_manager/server/templates/entities_history_template.ts
rename to x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_history_template.ts
index 63d589bfaa754..a0fb4b032a6e1 100644
--- a/x-pack/plugins/observability_solution/entity_manager/server/templates/entities_history_template.ts
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_history_template.ts
@@ -6,14 +6,14 @@
*/
import { IndicesPutIndexTemplateRequest } from '@elastic/elasticsearch/lib/api/types';
-import { getEntityHistoryIndexTemplateV1 } from '../../common/helpers';
+import { getEntityHistoryIndexTemplateV1 } from '../../../../common/helpers';
import {
ENTITY_ENTITY_COMPONENT_TEMPLATE_V1,
ENTITY_EVENT_COMPONENT_TEMPLATE_V1,
ENTITY_HISTORY_BASE_COMPONENT_TEMPLATE_V1,
ENTITY_HISTORY_INDEX_PREFIX_V1,
-} from '../../common/constants_entities';
-import { getCustomHistoryTemplateComponents } from './components/helpers';
+} from '../../../../common/constants_entities';
+import { getCustomHistoryTemplateComponents } from '../../../templates/components/helpers';
export const getEntitiesHistoryIndexTemplateConfig = (
definitionId: string
@@ -33,7 +33,7 @@ export const getEntitiesHistoryIndexTemplateConfig = (
ENTITY_EVENT_COMPONENT_TEMPLATE_V1,
...getCustomHistoryTemplateComponents(definitionId),
],
- index_patterns: [`${ENTITY_HISTORY_INDEX_PREFIX_V1}.*`],
+ index_patterns: [`${ENTITY_HISTORY_INDEX_PREFIX_V1}.${definitionId}.*`],
priority: 200,
template: {
mappings: {
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_latest_template.test.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_latest_template.test.ts
new file mode 100644
index 0000000000000..72583d941492c
--- /dev/null
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_latest_template.test.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.
+ */
+
+import { entityDefinition } from '../helpers/fixtures/entity_definition';
+import { getEntitiesLatestIndexTemplateConfig } from './entities_latest_template';
+
+describe('getEntitiesLatestIndexTemplateConfig(definitionId)', () => {
+ it('should generate a valid index template', () => {
+ const template = getEntitiesLatestIndexTemplateConfig(entityDefinition.id);
+ expect(template).toMatchSnapshot();
+ });
+});
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/templates/entities_latest_template.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_latest_template.ts
similarity index 87%
rename from x-pack/plugins/observability_solution/entity_manager/server/templates/entities_latest_template.ts
rename to x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_latest_template.ts
index 3ad09e7257a1a..466346f86b44d 100644
--- a/x-pack/plugins/observability_solution/entity_manager/server/templates/entities_latest_template.ts
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/templates/entities_latest_template.ts
@@ -6,14 +6,14 @@
*/
import { IndicesPutIndexTemplateRequest } from '@elastic/elasticsearch/lib/api/types';
-import { getEntityLatestIndexTemplateV1 } from '../../common/helpers';
+import { getEntityLatestIndexTemplateV1 } from '../../../../common/helpers';
import {
ENTITY_ENTITY_COMPONENT_TEMPLATE_V1,
ENTITY_EVENT_COMPONENT_TEMPLATE_V1,
ENTITY_LATEST_BASE_COMPONENT_TEMPLATE_V1,
ENTITY_LATEST_INDEX_PREFIX_V1,
-} from '../../common/constants_entities';
-import { getCustomLatestTemplateComponents } from './components/helpers';
+} from '../../../../common/constants_entities';
+import { getCustomLatestTemplateComponents } from '../../../templates/components/helpers';
export const getEntitiesLatestIndexTemplateConfig = (
definitionId: string
@@ -33,8 +33,8 @@ export const getEntitiesLatestIndexTemplateConfig = (
ENTITY_EVENT_COMPONENT_TEMPLATE_V1,
...getCustomLatestTemplateComponents(definitionId),
],
- index_patterns: [`${ENTITY_LATEST_INDEX_PREFIX_V1}.*`],
- priority: 1,
+ index_patterns: [`${ENTITY_LATEST_INDEX_PREFIX_V1}.${definitionId}`],
+ priority: 200,
template: {
mappings: {
_meta: {
diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/__snapshots__/generate_history_transform.test.ts.snap b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/__snapshots__/generate_history_transform.test.ts.snap
index 4ecdd0c3ab024..551b9761341d2 100644
--- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/__snapshots__/generate_history_transform.test.ts.snap
+++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/__snapshots__/generate_history_transform.test.ts.snap
@@ -9,7 +9,7 @@ Object {
"defer_validation": true,
"dest": Object {
"index": ".entities.v1.history.noop",
- "pipeline": "entities-v1-history-admin-console-services",
+ "pipeline": "entities-v1-history-admin-console-services-backfill",
},
"frequency": "5m",
"pivot": Object {
@@ -143,7 +143,7 @@ Object {
"field": "@timestamp",
},
},
- "transform_id": "entities-v1-history-backfill-admin-console-services",
+ "transform_id": "entities-v1-history-backfill-admin-console-services-backfill",
}
`;
diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml
new file mode 100644
index 0000000000000..22979d62e0933
--- /dev/null
+++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml
@@ -0,0 +1,938 @@
+openapi: 3.0.3
+info:
+ description: Interact with and manage endpoints running the Elastic Defend integration.
+ title: Security Solution Endpoint Management API (Elastic Cloud and self-hosted)
+ version: '2023-10-31'
+servers:
+ - url: 'http://{kibana_host}:{port}'
+ variables:
+ kibana_host:
+ default: localhost
+ port:
+ default: '5601'
+paths:
+ /api/endpoint/action:
+ get:
+ operationId: EndpointGetActionsList
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/EndpointActionListRequestQuery'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Actions List schema
+ '/api/endpoint/action_log/{agent_id}':
+ get:
+ operationId: EndpointGetActionAuditLog
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/AuditLogRequestQuery'
+ - in: path
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/AuditLogRequestParams'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get action audit log schema
+ /api/endpoint/action_status:
+ get:
+ operationId: EndpointGetActionsStatus
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ type: object
+ properties:
+ agent_ids:
+ $ref: '#/components/schemas/AgentIds'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Actions status schema
+ '/api/endpoint/action/{action_id}':
+ get:
+ operationId: EndpointGetActionsDetails
+ parameters:
+ - in: path
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/DetailsRequestParams'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Action details schema
+ '/api/endpoint/action/{action_id}/file/{file_id}/download`':
+ get:
+ operationId: EndpointFileDownload
+ parameters:
+ - in: path
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/FileDownloadRequestParams'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: File Download schema
+ '/api/endpoint/action/{action_id}/file/{file_id}`':
+ get:
+ operationId: EndpointFileInfo
+ parameters:
+ - in: path
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/FileInfoRequestParams'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: File Info schema
+ /api/endpoint/action/execute:
+ post:
+ operationId: EndpointExecuteAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExecuteActionRequestBody'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Execute Action
+ /api/endpoint/action/get_file:
+ post:
+ operationId: EndpointGetFileAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GetFileActionRequestBody'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get File Action
+ /api/endpoint/action/isolate:
+ post:
+ operationId: EndpointIsolateHostAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Isolate host Action
+ /api/endpoint/action/kill_process:
+ post:
+ operationId: EndpointKillProcessAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProcessActionSchemas'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Kill process Action
+ /api/endpoint/action/running_procs:
+ post:
+ operationId: EndpointGetRunningProcessesAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Running Processes Action
+ /api/endpoint/action/scan:
+ post:
+ operationId: EndpointScanAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ScanActionRequestBody'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Scan Action
+ /api/endpoint/action/state:
+ get:
+ operationId: EndpointGetActionsState
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Action State schema
+ /api/endpoint/action/suspend_process:
+ post:
+ operationId: EndpointSuspendProcessAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProcessActionSchemas'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Suspend process Action
+ /api/endpoint/action/unisolate:
+ post:
+ operationId: EndpointUnisolateHostAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Unisolate host Action
+ /api/endpoint/action/upload:
+ post:
+ operationId: EndpointUploadAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/FileUploadActionRequestBody'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Upload Action
+ /api/endpoint/isolate:
+ post:
+ operationId: EndpointIsolateRedirect
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ '308':
+ description: Permanent Redirect
+ headers:
+ Location:
+ description: Permanently redirects to "/api/endpoint/action/isolate"
+ schema:
+ example: /api/endpoint/action/isolate
+ type: string
+ summary: Permanently redirects to a new location
+ /api/endpoint/metadata:
+ get:
+ operationId: GetEndpointMetadataList
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/ListRequestQuery'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Metadata List schema
+ '/api/endpoint/metadata/{id}':
+ get:
+ operationId: GetEndpointMetadata
+ parameters:
+ - in: path
+ name: query
+ required: true
+ schema:
+ type: object
+ properties:
+ id:
+ type: string
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Metadata schema
+ /api/endpoint/metadata/transforms:
+ get:
+ operationId: GetEndpointMetadataTransform
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Metadata Transform schema
+ /api/endpoint/policy_response:
+ get:
+ operationId: GetPolicyResponse
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ type: object
+ properties:
+ agentId:
+ $ref: '#/components/schemas/AgentId'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Policy Response schema
+ /api/endpoint/policy/summaries:
+ get:
+ operationId: GetAgentPolicySummary
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ type: object
+ properties:
+ package_name:
+ type: string
+ policy_id:
+ nullable: true
+ type: string
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Agent Policy Summary schema
+ '/api/endpoint/protection_updates_note/{package_policy_id}':
+ get:
+ operationId: GetProtectionUpdatesNote
+ parameters:
+ - in: path
+ name: package_policy_id
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProtectionUpdatesNoteResponse'
+ description: OK
+ summary: Get Protection Updates Note schema
+ post:
+ operationId: CreateUpdateProtectionUpdatesNote
+ parameters:
+ - in: path
+ name: package_policy_id
+ required: true
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ note:
+ type: string
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProtectionUpdatesNoteResponse'
+ description: OK
+ summary: Create Update Protection Updates Note schema
+ '/api/endpoint/suggestions/{suggestion_type}':
+ post:
+ operationId: GetEndpointSuggestions
+ parameters:
+ - in: path
+ name: suggestion_type
+ required: true
+ schema:
+ enum:
+ - eventFilters
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ field:
+ type: string
+ fieldMeta: {}
+ filters: {}
+ query:
+ type: string
+ required:
+ - parameters
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get suggestions
+ /api/endpoint/unisolate:
+ post:
+ operationId: EndpointUnisolateRedirect
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ '308':
+ description: Permanent Redirect
+ headers:
+ Location:
+ description: Permanently redirects to "/api/endpoint/action/unisolate"
+ schema:
+ example: /api/endpoint/action/unisolate
+ type: string
+ summary: Permanently redirects to a new location
+components:
+ schemas:
+ AgentId:
+ description: Agent ID
+ type: string
+ AgentIds:
+ minLength: 1
+ oneOf:
+ - items:
+ minLength: 1
+ type: string
+ maxItems: 50
+ minItems: 1
+ type: array
+ - minLength: 1
+ type: string
+ AlertIds:
+ description: A list of alerts ids.
+ items:
+ $ref: '#/components/schemas/NonEmptyString'
+ minItems: 1
+ type: array
+ AuditLogRequestParams:
+ type: object
+ properties:
+ agent_id:
+ $ref: '#/components/schemas/AgentId'
+ AuditLogRequestQuery:
+ type: object
+ properties:
+ end_date:
+ $ref: '#/components/schemas/EndDate'
+ page:
+ $ref: '#/components/schemas/Page'
+ page_size:
+ $ref: '#/components/schemas/PageSize'
+ start_date:
+ $ref: '#/components/schemas/StartDate'
+ CaseIds:
+ description: Case IDs to be updated (cannot contain empty strings)
+ items:
+ minLength: 1
+ type: string
+ minItems: 1
+ type: array
+ Command:
+ description: The command to be executed (cannot be an empty string)
+ enum:
+ - isolate
+ - unisolate
+ - kill-process
+ - suspend-process
+ - running-processes
+ - get-file
+ - execute
+ - upload
+ minLength: 1
+ type: string
+ Commands:
+ items:
+ $ref: '#/components/schemas/Command'
+ type: array
+ Comment:
+ description: Optional comment
+ type: string
+ DetailsRequestParams:
+ type: object
+ properties:
+ action_id:
+ type: string
+ EndDate:
+ description: End date
+ type: string
+ EndpointActionListRequestQuery:
+ type: object
+ properties:
+ agentIds:
+ $ref: '#/components/schemas/AgentIds'
+ commands:
+ $ref: '#/components/schemas/Commands'
+ endDate:
+ $ref: '#/components/schemas/EndDate'
+ page:
+ $ref: '#/components/schemas/Page'
+ pageSize:
+ default: 10
+ description: Number of items per page
+ maximum: 10000
+ minimum: 1
+ type: integer
+ startDate:
+ $ref: '#/components/schemas/StartDate'
+ types:
+ $ref: '#/components/schemas/Types'
+ userIds:
+ $ref: '#/components/schemas/UserIds'
+ withOutputs:
+ $ref: '#/components/schemas/WithOutputs'
+ EndpointIds:
+ description: List of endpoint IDs (cannot contain empty strings)
+ items:
+ minLength: 1
+ type: string
+ minItems: 1
+ type: array
+ ExecuteActionRequestBody:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ parameters:
+ type: object
+ properties:
+ command:
+ $ref: '#/components/schemas/Command'
+ timeout:
+ $ref: '#/components/schemas/Timeout'
+ required:
+ - command
+ required:
+ - parameters
+ FileDownloadRequestParams:
+ type: object
+ properties:
+ action_id:
+ type: string
+ file_id:
+ type: string
+ required:
+ - action_id
+ - file_id
+ FileInfoRequestParams:
+ type: object
+ properties:
+ action_id:
+ type: string
+ file_id:
+ type: string
+ required:
+ - action_id
+ - file_id
+ FileUploadActionRequestBody:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ file:
+ format: binary
+ type: string
+ parameters:
+ type: object
+ properties:
+ overwrite:
+ default: false
+ type: boolean
+ required:
+ - parameters
+ - file
+ GetFileActionRequestBody:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ parameters:
+ type: object
+ properties:
+ path:
+ type: string
+ required:
+ - path
+ required:
+ - parameters
+ ListRequestQuery:
+ type: object
+ properties:
+ hostStatuses:
+ items:
+ enum:
+ - healthy
+ - offline
+ - updating
+ - inactive
+ - unenrolled
+ type: string
+ type: array
+ kuery:
+ nullable: true
+ type: string
+ page:
+ default: 0
+ description: Page number
+ minimum: 0
+ type: integer
+ pageSize:
+ default: 10
+ description: Number of items per page
+ maximum: 10000
+ minimum: 1
+ type: integer
+ sortDirection:
+ enum:
+ - asc
+ - desc
+ nullable: true
+ type: string
+ sortField:
+ enum:
+ - enrolled_at
+ - metadata.host.hostname
+ - host_status
+ - metadata.Endpoint.policy.applied.name
+ - metadata.Endpoint.policy.applied.status
+ - metadata.host.os.name
+ - metadata.host.ip
+ - metadata.agent.version
+ - last_checkin
+ type: string
+ required:
+ - hostStatuses
+ NonEmptyString:
+ description: A string that is not empty and does not contain only whitespace
+ minLength: 1
+ pattern: ^(?! *$).+$
+ type: string
+ Page:
+ default: 1
+ description: Page number
+ minimum: 1
+ type: integer
+ PageSize:
+ default: 10
+ description: Number of items per page
+ maximum: 100
+ minimum: 1
+ type: integer
+ Parameters:
+ description: Optional parameters object
+ type: object
+ ProcessActionSchemas:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ parameters:
+ oneOf:
+ - type: object
+ properties:
+ pid:
+ minimum: 1
+ type: integer
+ - type: object
+ properties:
+ entity_id:
+ minLength: 1
+ type: string
+ required:
+ - parameters
+ ProtectionUpdatesNoteResponse:
+ type: object
+ properties:
+ note:
+ type: string
+ ScanActionRequestBody:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ parameters:
+ type: object
+ properties:
+ path:
+ type: string
+ required:
+ - path
+ required:
+ - parameters
+ StartDate:
+ description: Start date
+ type: string
+ SuccessResponse:
+ type: object
+ properties: {}
+ Timeout:
+ description: The maximum timeout value in milliseconds (optional)
+ minimum: 1
+ type: integer
+ Type:
+ enum:
+ - automated
+ - manual
+ type: string
+ Types:
+ items:
+ $ref: '#/components/schemas/Type'
+ maxLength: 2
+ minLength: 1
+ type: array
+ UserIds:
+ description: User IDs
+ oneOf:
+ - items:
+ minLength: 1
+ type: string
+ minItems: 1
+ type: array
+ - minLength: 1
+ type: string
+ WithOutputs:
+ description: With Outputs
+ oneOf:
+ - items:
+ minLength: 1
+ type: string
+ minItems: 1
+ type: array
+ - minLength: 1
+ type: string
+ securitySchemes:
+ BasicAuth:
+ scheme: basic
+ type: http
+security:
+ - BasicAuth: []
+tags: ! ''
diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml
new file mode 100644
index 0000000000000..99627f8bd8a9e
--- /dev/null
+++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml
@@ -0,0 +1,866 @@
+openapi: 3.0.3
+info:
+ description: Interact with and manage endpoints running the Elastic Defend integration.
+ title: Security Solution Endpoint Management API (Elastic Cloud Serverless)
+ version: '2023-10-31'
+servers:
+ - url: 'http://{kibana_host}:{port}'
+ variables:
+ kibana_host:
+ default: localhost
+ port:
+ default: '5601'
+paths:
+ /api/endpoint/action:
+ get:
+ operationId: EndpointGetActionsList
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/EndpointActionListRequestQuery'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Actions List schema
+ '/api/endpoint/action_log/{agent_id}':
+ get:
+ operationId: EndpointGetActionAuditLog
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/AuditLogRequestQuery'
+ - in: path
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/AuditLogRequestParams'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get action audit log schema
+ /api/endpoint/action_status:
+ get:
+ operationId: EndpointGetActionsStatus
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ type: object
+ properties:
+ agent_ids:
+ $ref: '#/components/schemas/AgentIds'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Actions status schema
+ '/api/endpoint/action/{action_id}':
+ get:
+ operationId: EndpointGetActionsDetails
+ parameters:
+ - in: path
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/DetailsRequestParams'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Action details schema
+ '/api/endpoint/action/{action_id}/file/{file_id}/download`':
+ get:
+ operationId: EndpointFileDownload
+ parameters:
+ - in: path
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/FileDownloadRequestParams'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: File Download schema
+ '/api/endpoint/action/{action_id}/file/{file_id}`':
+ get:
+ operationId: EndpointFileInfo
+ parameters:
+ - in: path
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/FileInfoRequestParams'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: File Info schema
+ /api/endpoint/action/execute:
+ post:
+ operationId: EndpointExecuteAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExecuteActionRequestBody'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Execute Action
+ /api/endpoint/action/get_file:
+ post:
+ operationId: EndpointGetFileAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GetFileActionRequestBody'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get File Action
+ /api/endpoint/action/isolate:
+ post:
+ operationId: EndpointIsolateHostAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Isolate host Action
+ /api/endpoint/action/kill_process:
+ post:
+ operationId: EndpointKillProcessAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProcessActionSchemas'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Kill process Action
+ /api/endpoint/action/running_procs:
+ post:
+ operationId: EndpointGetRunningProcessesAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Running Processes Action
+ /api/endpoint/action/scan:
+ post:
+ operationId: EndpointScanAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ScanActionRequestBody'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Scan Action
+ /api/endpoint/action/state:
+ get:
+ operationId: EndpointGetActionsState
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Action State schema
+ /api/endpoint/action/suspend_process:
+ post:
+ operationId: EndpointSuspendProcessAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProcessActionSchemas'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Suspend process Action
+ /api/endpoint/action/unisolate:
+ post:
+ operationId: EndpointUnisolateHostAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Unisolate host Action
+ /api/endpoint/action/upload:
+ post:
+ operationId: EndpointUploadAction
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/FileUploadActionRequestBody'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Upload Action
+ /api/endpoint/metadata:
+ get:
+ operationId: GetEndpointMetadataList
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ $ref: '#/components/schemas/ListRequestQuery'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Metadata List schema
+ '/api/endpoint/metadata/{id}':
+ get:
+ operationId: GetEndpointMetadata
+ parameters:
+ - in: path
+ name: query
+ required: true
+ schema:
+ type: object
+ properties:
+ id:
+ type: string
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Metadata schema
+ /api/endpoint/metadata/transforms:
+ get:
+ operationId: GetEndpointMetadataTransform
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Metadata Transform schema
+ /api/endpoint/policy_response:
+ get:
+ operationId: GetPolicyResponse
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ type: object
+ properties:
+ agentId:
+ $ref: '#/components/schemas/AgentId'
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Policy Response schema
+ /api/endpoint/policy/summaries:
+ get:
+ operationId: GetAgentPolicySummary
+ parameters:
+ - in: query
+ name: query
+ required: true
+ schema:
+ type: object
+ properties:
+ package_name:
+ type: string
+ policy_id:
+ nullable: true
+ type: string
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get Agent Policy Summary schema
+ '/api/endpoint/protection_updates_note/{package_policy_id}':
+ get:
+ operationId: GetProtectionUpdatesNote
+ parameters:
+ - in: path
+ name: package_policy_id
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProtectionUpdatesNoteResponse'
+ description: OK
+ summary: Get Protection Updates Note schema
+ post:
+ operationId: CreateUpdateProtectionUpdatesNote
+ parameters:
+ - in: path
+ name: package_policy_id
+ required: true
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ note:
+ type: string
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProtectionUpdatesNoteResponse'
+ description: OK
+ summary: Create Update Protection Updates Note schema
+ '/api/endpoint/suggestions/{suggestion_type}':
+ post:
+ operationId: GetEndpointSuggestions
+ parameters:
+ - in: path
+ name: suggestion_type
+ required: true
+ schema:
+ enum:
+ - eventFilters
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ field:
+ type: string
+ fieldMeta: {}
+ filters: {}
+ query:
+ type: string
+ required:
+ - parameters
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessResponse'
+ description: OK
+ summary: Get suggestions
+components:
+ schemas:
+ AgentId:
+ description: Agent ID
+ type: string
+ AgentIds:
+ minLength: 1
+ oneOf:
+ - items:
+ minLength: 1
+ type: string
+ maxItems: 50
+ minItems: 1
+ type: array
+ - minLength: 1
+ type: string
+ AlertIds:
+ description: A list of alerts ids.
+ items:
+ $ref: '#/components/schemas/NonEmptyString'
+ minItems: 1
+ type: array
+ AuditLogRequestParams:
+ type: object
+ properties:
+ agent_id:
+ $ref: '#/components/schemas/AgentId'
+ AuditLogRequestQuery:
+ type: object
+ properties:
+ end_date:
+ $ref: '#/components/schemas/EndDate'
+ page:
+ $ref: '#/components/schemas/Page'
+ page_size:
+ $ref: '#/components/schemas/PageSize'
+ start_date:
+ $ref: '#/components/schemas/StartDate'
+ CaseIds:
+ description: Case IDs to be updated (cannot contain empty strings)
+ items:
+ minLength: 1
+ type: string
+ minItems: 1
+ type: array
+ Command:
+ description: The command to be executed (cannot be an empty string)
+ enum:
+ - isolate
+ - unisolate
+ - kill-process
+ - suspend-process
+ - running-processes
+ - get-file
+ - execute
+ - upload
+ minLength: 1
+ type: string
+ Commands:
+ items:
+ $ref: '#/components/schemas/Command'
+ type: array
+ Comment:
+ description: Optional comment
+ type: string
+ DetailsRequestParams:
+ type: object
+ properties:
+ action_id:
+ type: string
+ EndDate:
+ description: End date
+ type: string
+ EndpointActionListRequestQuery:
+ type: object
+ properties:
+ agentIds:
+ $ref: '#/components/schemas/AgentIds'
+ commands:
+ $ref: '#/components/schemas/Commands'
+ endDate:
+ $ref: '#/components/schemas/EndDate'
+ page:
+ $ref: '#/components/schemas/Page'
+ pageSize:
+ default: 10
+ description: Number of items per page
+ maximum: 10000
+ minimum: 1
+ type: integer
+ startDate:
+ $ref: '#/components/schemas/StartDate'
+ types:
+ $ref: '#/components/schemas/Types'
+ userIds:
+ $ref: '#/components/schemas/UserIds'
+ withOutputs:
+ $ref: '#/components/schemas/WithOutputs'
+ EndpointIds:
+ description: List of endpoint IDs (cannot contain empty strings)
+ items:
+ minLength: 1
+ type: string
+ minItems: 1
+ type: array
+ ExecuteActionRequestBody:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ parameters:
+ type: object
+ properties:
+ command:
+ $ref: '#/components/schemas/Command'
+ timeout:
+ $ref: '#/components/schemas/Timeout'
+ required:
+ - command
+ required:
+ - parameters
+ FileDownloadRequestParams:
+ type: object
+ properties:
+ action_id:
+ type: string
+ file_id:
+ type: string
+ required:
+ - action_id
+ - file_id
+ FileInfoRequestParams:
+ type: object
+ properties:
+ action_id:
+ type: string
+ file_id:
+ type: string
+ required:
+ - action_id
+ - file_id
+ FileUploadActionRequestBody:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ file:
+ format: binary
+ type: string
+ parameters:
+ type: object
+ properties:
+ overwrite:
+ default: false
+ type: boolean
+ required:
+ - parameters
+ - file
+ GetFileActionRequestBody:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ parameters:
+ type: object
+ properties:
+ path:
+ type: string
+ required:
+ - path
+ required:
+ - parameters
+ ListRequestQuery:
+ type: object
+ properties:
+ hostStatuses:
+ items:
+ enum:
+ - healthy
+ - offline
+ - updating
+ - inactive
+ - unenrolled
+ type: string
+ type: array
+ kuery:
+ nullable: true
+ type: string
+ page:
+ default: 0
+ description: Page number
+ minimum: 0
+ type: integer
+ pageSize:
+ default: 10
+ description: Number of items per page
+ maximum: 10000
+ minimum: 1
+ type: integer
+ sortDirection:
+ enum:
+ - asc
+ - desc
+ nullable: true
+ type: string
+ sortField:
+ enum:
+ - enrolled_at
+ - metadata.host.hostname
+ - host_status
+ - metadata.Endpoint.policy.applied.name
+ - metadata.Endpoint.policy.applied.status
+ - metadata.host.os.name
+ - metadata.host.ip
+ - metadata.agent.version
+ - last_checkin
+ type: string
+ required:
+ - hostStatuses
+ NonEmptyString:
+ description: A string that is not empty and does not contain only whitespace
+ minLength: 1
+ pattern: ^(?! *$).+$
+ type: string
+ Page:
+ default: 1
+ description: Page number
+ minimum: 1
+ type: integer
+ PageSize:
+ default: 10
+ description: Number of items per page
+ maximum: 100
+ minimum: 1
+ type: integer
+ Parameters:
+ description: Optional parameters object
+ type: object
+ ProcessActionSchemas:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ parameters:
+ oneOf:
+ - type: object
+ properties:
+ pid:
+ minimum: 1
+ type: integer
+ - type: object
+ properties:
+ entity_id:
+ minLength: 1
+ type: string
+ required:
+ - parameters
+ ProtectionUpdatesNoteResponse:
+ type: object
+ properties:
+ note:
+ type: string
+ ScanActionRequestBody:
+ allOf:
+ - type: object
+ properties:
+ alert_ids:
+ $ref: '#/components/schemas/AlertIds'
+ case_ids:
+ $ref: '#/components/schemas/CaseIds'
+ comment:
+ $ref: '#/components/schemas/Comment'
+ endpoint_ids:
+ $ref: '#/components/schemas/EndpointIds'
+ parameters:
+ $ref: '#/components/schemas/Parameters'
+ - type: object
+ properties:
+ parameters:
+ type: object
+ properties:
+ path:
+ type: string
+ required:
+ - path
+ required:
+ - parameters
+ StartDate:
+ description: Start date
+ type: string
+ SuccessResponse:
+ type: object
+ properties: {}
+ Timeout:
+ description: The maximum timeout value in milliseconds (optional)
+ minimum: 1
+ type: integer
+ Type:
+ enum:
+ - automated
+ - manual
+ type: string
+ Types:
+ items:
+ $ref: '#/components/schemas/Type'
+ maxLength: 2
+ minLength: 1
+ type: array
+ UserIds:
+ description: User IDs
+ oneOf:
+ - items:
+ minLength: 1
+ type: string
+ minItems: 1
+ type: array
+ - minLength: 1
+ type: string
+ WithOutputs:
+ description: With Outputs
+ oneOf:
+ - items:
+ minLength: 1
+ type: string
+ minItems: 1
+ type: array
+ - minLength: 1
+ type: string
+ securitySchemes:
+ BasicAuth:
+ scheme: basic
+ type: http
+security:
+ - BasicAuth: []
+tags: ! ''
diff --git a/x-pack/plugins/security_solution/package.json b/x-pack/plugins/security_solution/package.json
index cd7eb82b11a92..98575c1f48c26 100644
--- a/x-pack/plugins/security_solution/package.json
+++ b/x-pack/plugins/security_solution/package.json
@@ -32,6 +32,7 @@
"openapi:generate:debug": "node --inspect-brk scripts/openapi/generate",
"openapi:bundle:detections": "node scripts/openapi/bundle_detections",
"openapi:bundle:timeline": "node scripts/openapi/bundle_timeline",
- "openapi:bundle:entity-analytics": "node scripts/openapi/bundle_entity_analytics"
+ "openapi:bundle:entity-analytics": "node scripts/openapi/bundle_entity_analytics",
+ "openapi:bundle:endpoint-management": "node scripts/openapi/bundle_endpoint_management"
}
}
diff --git a/x-pack/plugins/security_solution/scripts/openapi/bundle_endpoint_management.js b/x-pack/plugins/security_solution/scripts/openapi/bundle_endpoint_management.js
new file mode 100644
index 0000000000000..d4d994b993057
--- /dev/null
+++ b/x-pack/plugins/security_solution/scripts/openapi/bundle_endpoint_management.js
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+require('../../../../../src/setup_node_env');
+const { bundle } = require('@kbn/openapi-bundler');
+const { join, resolve } = require('path');
+
+const ROOT = resolve(__dirname, '../..');
+
+(async () => {
+ await bundle({
+ sourceGlob: join(ROOT, 'common/api/endpoint/**/*.schema.yaml'),
+ outputFilePath: join(
+ ROOT,
+ 'docs/openapi/serverless/security_solution_endpoint_management_api_{version}.bundled.schema.yaml'
+ ),
+ options: {
+ includeLabels: ['serverless'],
+ specInfo: {
+ title: 'Security Solution Endpoint Management API (Elastic Cloud Serverless)',
+ description: 'Interact with and manage endpoints running the Elastic Defend integration.',
+ },
+ },
+ });
+
+ await bundle({
+ sourceGlob: join(ROOT, 'common/api/endpoint/**/*.schema.yaml'),
+ outputFilePath: join(
+ ROOT,
+ 'docs/openapi/ess/security_solution_endpoint_management_api_{version}.bundled.schema.yaml'
+ ),
+ options: {
+ includeLabels: ['ess'],
+ specInfo: {
+ title: 'Security Solution Endpoint Management API (Elastic Cloud and self-hosted)',
+ description: 'Interact with and manage endpoints running the Elastic Defend integration.',
+ },
+ },
+ });
+})();
diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/async_sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/async_sender.ts
index 6c2def2abb61d..edbd5d21e3aea 100644
--- a/x-pack/plugins/security_solution/server/lib/telemetry/async_sender.ts
+++ b/x-pack/plugins/security_solution/server/lib/telemetry/async_sender.ts
@@ -276,28 +276,15 @@ export class AsyncTelemetryEventsSender implements IAsyncTelemetryEventsSender {
private enrich(event: Event): Event {
const clusterInfo = this.telemetryReceiver?.getClusterInfo();
- // TODO(szaffarano): generalize the enrichment at channel level to not hardcode the logic here
if (typeof event.payload === 'object') {
let additional = {};
- if (event.channel !== TelemetryChannel.TASK_METRICS) {
- additional = {
- cluster_name: clusterInfo?.cluster_name,
- cluster_uuid: clusterInfo?.cluster_uuid,
- };
- } else {
- additional = {
- cluster_uuid: clusterInfo?.cluster_uuid,
- };
- }
-
- if (event.channel === TelemetryChannel.ENDPOINT_ALERTS) {
- const licenseInfo = this.telemetryReceiver?.getLicenseInfo();
- additional = {
- ...additional,
- ...(licenseInfo ? { license: copyLicenseFields(licenseInfo) } : {}),
- };
- }
+ const licenseInfo = this.telemetryReceiver?.getLicenseInfo();
+ additional = {
+ cluster_name: clusterInfo?.cluster_name,
+ cluster_uuid: clusterInfo?.cluster_uuid,
+ ...(licenseInfo ? { license: copyLicenseFields(licenseInfo) } : {}),
+ };
event.payload = {
...event.payload,
diff --git a/x-pack/plugins/task_manager/server/integration_tests/__snapshots__/task_cost_check.test.ts.snap b/x-pack/plugins/task_manager/server/integration_tests/__snapshots__/task_cost_check.test.ts.snap
new file mode 100644
index 0000000000000..e59912ed91905
--- /dev/null
+++ b/x-pack/plugins/task_manager/server/integration_tests/__snapshots__/task_cost_check.test.ts.snap
@@ -0,0 +1,10 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Task cost checks detects tasks with cost definitions 1`] = `
+Array [
+ Object {
+ "cost": 10,
+ "taskType": "alerting:siem.indicatorRule",
+ },
+]
+`;
diff --git a/x-pack/plugins/task_manager/server/integration_tests/task_cost_check.test.ts b/x-pack/plugins/task_manager/server/integration_tests/task_cost_check.test.ts
new file mode 100644
index 0000000000000..96678f714ac69
--- /dev/null
+++ b/x-pack/plugins/task_manager/server/integration_tests/task_cost_check.test.ts
@@ -0,0 +1,63 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import {
+ type TestElasticsearchUtils,
+ type TestKibanaUtils,
+} from '@kbn/core-test-helpers-kbn-server';
+import { TaskCost, TaskDefinition } from '../task';
+import { setupTestServers } from './lib';
+import { TaskTypeDictionary } from '../task_type_dictionary';
+
+jest.mock('../task_type_dictionary', () => {
+ const actual = jest.requireActual('../task_type_dictionary');
+ return {
+ ...actual,
+ TaskTypeDictionary: jest.fn().mockImplementation((opts) => {
+ return new actual.TaskTypeDictionary(opts);
+ }),
+ };
+});
+
+// Notify response-ops if a task sets a cost to something other than `Normal`
+describe('Task cost checks', () => {
+ let esServer: TestElasticsearchUtils;
+ let kibanaServer: TestKibanaUtils;
+ let taskTypeDictionary: TaskTypeDictionary;
+
+ beforeAll(async () => {
+ const setupResult = await setupTestServers();
+ esServer = setupResult.esServer;
+ kibanaServer = setupResult.kibanaServer;
+
+ const mockedTaskTypeDictionary = jest.requireMock('../task_type_dictionary');
+ expect(mockedTaskTypeDictionary.TaskTypeDictionary).toHaveBeenCalledTimes(1);
+ taskTypeDictionary = mockedTaskTypeDictionary.TaskTypeDictionary.mock.results[0].value;
+ });
+
+ afterAll(async () => {
+ if (kibanaServer) {
+ await kibanaServer.stop();
+ }
+ if (esServer) {
+ await esServer.stop();
+ }
+ });
+
+ it('detects tasks with cost definitions', async () => {
+ const taskTypes = taskTypeDictionary.getAllDefinitions();
+ const taskTypesWithCost = taskTypes
+ .map((taskType: TaskDefinition) =>
+ !!taskType.cost ? { taskType: taskType.type, cost: taskType.cost } : null
+ )
+ .filter(
+ (tt: { taskType: string; cost: TaskCost } | null) =>
+ null != tt && tt.cost !== TaskCost.Normal
+ );
+ expect(taskTypesWithCost).toMatchSnapshot();
+ });
+});
diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/monitoring_collection.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/monitoring_collection.ts
index f87c1c095dd8f..902362f9fc31c 100644
--- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/monitoring_collection.ts
+++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/monitoring_collection.ts
@@ -38,8 +38,7 @@ export default function alertingMonitoringCollectionTests({ getService }: FtrPro
? dedicatedTaskRunner.getSupertest()
: supertest;
- // Failing: See https://github.com/elastic/kibana/issues/187275
- describe.skip('monitoring_collection', () => {
+ describe('monitoring_collection', () => {
let endDate: string;
const objectRemover = new ObjectRemover(supertest);
@@ -124,8 +123,8 @@ export default function alertingMonitoringCollectionTests({ getService }: FtrPro
rule_type_id: 'test.cancellableRule',
schedule: { interval: '4s' },
params: {
- doLongSearch: true,
- doLongPostProcessing: false,
+ doLongSearch: false,
+ doLongPostProcessing: true,
},
})
);
diff --git a/x-pack/test/api_integration/apis/entity_manager/definitions.ts b/x-pack/test/api_integration/apis/entity_manager/definitions.ts
new file mode 100644
index 0000000000000..89b6bae918fbb
--- /dev/null
+++ b/x-pack/test/api_integration/apis/entity_manager/definitions.ts
@@ -0,0 +1,42 @@
+/*
+ * 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 { EntityDefinition } from '@kbn/entities-schema';
+import {
+ entityDefinition as mockDefinition,
+ entityDefinitionWithBackfill as mockBackfillDefinition,
+} from '@kbn/entityManager-plugin/server/lib/entities/helpers/fixtures';
+import { FtrProviderContext } from '../../ftr_provider_context';
+import { installDefinition, uninstallDefinition, getInstalledDefinitions } from './helpers/request';
+
+export default function ({ getService }: FtrProviderContext) {
+ const supertest = getService('supertest');
+
+ describe('Entity definitions', () => {
+ describe('definitions installations', () => {
+ it('can install multiple definitions', async () => {
+ await installDefinition(supertest, mockDefinition);
+ await installDefinition(supertest, mockBackfillDefinition);
+
+ const { definitions } = await getInstalledDefinitions(supertest);
+ expect(definitions.length).to.eql(2);
+ expect(
+ definitions.find((definition: EntityDefinition) => definition.id === mockDefinition.id)
+ );
+ expect(
+ definitions.find(
+ (definition: EntityDefinition) => definition.id === mockBackfillDefinition.id
+ )
+ );
+
+ await uninstallDefinition(supertest, mockDefinition.id);
+ await uninstallDefinition(supertest, mockBackfillDefinition.id);
+ });
+ });
+ });
+}
diff --git a/x-pack/test/api_integration/apis/entity_manager/enablement.ts b/x-pack/test/api_integration/apis/entity_manager/enablement.ts
index 8ec5f6743a51f..a84a293e36caf 100644
--- a/x-pack/test/api_integration/apis/entity_manager/enablement.ts
+++ b/x-pack/test/api_integration/apis/entity_manager/enablement.ts
@@ -11,11 +11,7 @@ import { builtInDefinitions } from '@kbn/entityManager-plugin/server/lib/entitie
import { EntityDefinitionWithState } from '@kbn/entityManager-plugin/server/lib/entities/types';
import { FtrProviderContext } from '../../ftr_provider_context';
import { createAdmin, createRuntimeUser } from './helpers/user';
-
-interface Auth {
- username: string;
- password: string;
-}
+import { Auth, getInstalledDefinitions } from './helpers/request';
export default function ({ getService }: FtrProviderContext) {
const esClient = getService('es');
@@ -32,16 +28,6 @@ export default function ({ getService }: FtrProviderContext) {
return response.body;
};
- const getInstalledDefinitions = async (auth: Auth) => {
- const response = await supertest
- .get('/internal/entities/definition')
- .auth(auth.username, auth.password)
- .set('kbn-xsrf', 'xxx')
- .send()
- .expect(200);
- return response.body;
- };
-
const entityDiscoveryState = enablementRequest('get');
const enableEntityDiscovery = enablementRequest('put');
const disableEntityDiscovery = enablementRequest('delete');
@@ -62,7 +48,7 @@ export default function ({ getService }: FtrProviderContext) {
const enableResponse = await enableEntityDiscovery(authorizedUser);
expect(enableResponse.success).to.eql(true, "authorized user can't enable EEM");
- let definitionsResponse = await getInstalledDefinitions(authorizedUser);
+ let definitionsResponse = await getInstalledDefinitions(supertest, authorizedUser);
expect(definitionsResponse.definitions.length).to.eql(builtInDefinitions.length);
expect(
builtInDefinitions.every((builtin) => {
@@ -93,7 +79,7 @@ export default function ({ getService }: FtrProviderContext) {
stateResponse = await entityDiscoveryState(authorizedUser);
expect(stateResponse.enabled).to.eql(false, 'EEM is not disabled');
- definitionsResponse = await getInstalledDefinitions(authorizedUser);
+ definitionsResponse = await getInstalledDefinitions(supertest, authorizedUser);
expect(definitionsResponse.definitions).to.eql([]);
});
});
@@ -107,7 +93,7 @@ export default function ({ getService }: FtrProviderContext) {
const stateResponse = await entityDiscoveryState(unauthorizedUser);
expect(stateResponse.enabled).to.eql(false, 'EEM is enabled');
- const definitionsResponse = await getInstalledDefinitions(unauthorizedUser);
+ const definitionsResponse = await getInstalledDefinitions(supertest, unauthorizedUser);
expect(definitionsResponse.definitions).to.eql([]);
});
@@ -115,11 +101,11 @@ export default function ({ getService }: FtrProviderContext) {
const enableResponse = await enableEntityDiscovery(authorizedUser);
expect(enableResponse.success).to.eql(true, "authorized user can't enable EEM");
- let disableResponse = await enableEntityDiscovery(unauthorizedUser);
+ let disableResponse = await disableEntityDiscovery(unauthorizedUser);
expect(disableResponse.success).to.eql(false, 'unauthorized user can disable EEM');
expect(disableResponse.reason).to.eql(ERROR_USER_NOT_AUTHORIZED);
- disableResponse = await enableEntityDiscovery(authorizedUser);
+ disableResponse = await disableEntityDiscovery(authorizedUser);
expect(disableResponse.success).to.eql(true, "authorized user can't disable EEM");
});
});
diff --git a/x-pack/test/api_integration/apis/entity_manager/helpers/request.ts b/x-pack/test/api_integration/apis/entity_manager/helpers/request.ts
new file mode 100644
index 0000000000000..edb1ccda18f6a
--- /dev/null
+++ b/x-pack/test/api_integration/apis/entity_manager/helpers/request.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 { Agent } from 'supertest';
+import { EntityDefinition } from '@kbn/entities-schema';
+
+export interface Auth {
+ username: string;
+ password: string;
+}
+
+export const getInstalledDefinitions = async (supertest: Agent, auth?: Auth) => {
+ let req = supertest.get('/internal/entities/definition').set('kbn-xsrf', 'xxx');
+ if (auth) {
+ req = req.auth(auth.username, auth.password);
+ }
+ const response = await req.send().expect(200);
+ return response.body;
+};
+
+export const installDefinition = async (supertest: Agent, definition: EntityDefinition) => {
+ return supertest
+ .post('/internal/entities/definition')
+ .set('kbn-xsrf', 'xxx')
+ .send(definition)
+ .expect(200);
+};
+
+export const uninstallDefinition = (supertest: Agent, id: string) => {
+ return supertest
+ .delete(`/internal/entities/definition/${id}`)
+ .set('kbn-xsrf', 'xxx')
+ .send()
+ .expect(200);
+};
diff --git a/x-pack/test/api_integration/apis/entity_manager/index.ts b/x-pack/test/api_integration/apis/entity_manager/index.ts
index 74a5493401fa3..b6876849ef682 100644
--- a/x-pack/test/api_integration/apis/entity_manager/index.ts
+++ b/x-pack/test/api_integration/apis/entity_manager/index.ts
@@ -12,5 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
this.tags(['entityManager']);
loadTestFile(require.resolve('./enablement'));
+ loadTestFile(require.resolve('./definitions'));
});
}
diff --git a/x-pack/test/functional/page_objects/search_playground_page.ts b/x-pack/test/functional/page_objects/search_playground_page.ts
index 97e53e87ed2f9..8e59c7cc3e37a 100644
--- a/x-pack/test/functional/page_objects/search_playground_page.ts
+++ b/x-pack/test/functional/page_objects/search_playground_page.ts
@@ -54,6 +54,13 @@ export function SearchPlaygroundPageProvider({ getService }: FtrProviderContext)
await testSubjects.existOrFail('connectLLMButton');
},
+ async expectPlaygroundLLMConnectorOptionsExists() {
+ await testSubjects.existOrFail('create-connector-flyout');
+ await testSubjects.existOrFail('.gemini-card');
+ await testSubjects.existOrFail('.bedrock-card');
+ await testSubjects.existOrFail('.gen-ai-card');
+ },
+
async expectPlaygroundStartChatPageIndexButtonExists() {
await testSubjects.existOrFail('createIndexButton');
},
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/remove_time_fields_from_telemetry_stats.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/remove_time_fields_from_telemetry_stats.ts
index 912649862a24f..2d27b375684ba 100644
--- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/remove_time_fields_from_telemetry_stats.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/remove_time_fields_from_telemetry_stats.ts
@@ -15,6 +15,8 @@ export const removeExtraFieldsFromTelemetryStats = (stats: any) => {
unset(value, `[${i}][${j}].start_time`);
unset(value, `[${i}][${j}].end_time`);
unset(value, `[${i}][${j}].cluster_uuid`);
+ unset(value, `[${i}][${j}].cluster_name`);
+ unset(value, `[${i}][${j}].license`);
});
});
});
diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json
index 4b07d1fa44d7d..6e05b3d929fbe 100644
--- a/x-pack/test/tsconfig.json
+++ b/x-pack/test/tsconfig.json
@@ -175,6 +175,7 @@
"@kbn/securitysolution-lists-common",
"@kbn/securitysolution-exceptions-common",
"@kbn/entityManager-plugin",
- "@kbn/osquery-plugin"
+ "@kbn/osquery-plugin",
+ "@kbn/entities-schema"
]
}
diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts
index ad873c2bc9ce4..51a0d3f03be8f 100644
--- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts
+++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts
@@ -5,6 +5,7 @@
* 2.0.
*/
+import expect from 'expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { InternalRequestHeader, RoleCredentials } from '../../../../shared/services';
@@ -24,13 +25,40 @@ export default function ({ getService }: FtrProviderContext) {
await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc);
});
describe('route access', () => {
- describe('disabled', () => {
+ describe('internal', () => {
it('rotate key', async () => {
- const { body, status } = await supertestWithoutAuth
+ let body: unknown;
+ let status: number;
+
+ ({ body, status } = await supertestWithoutAuth
+ .post('/api/encrypted_saved_objects/_rotate_key')
+ // .set(internalReqHeader)
+ .set(roleAuthc.apiKeyHeader));
+ // svlCommonApi.assertApiNotFound(body, status);
+ // expect a rejection because we're not using the internal header
+ expect(body).toEqual({
+ statusCode: 400,
+ error: 'Bad Request',
+ message: expect.stringContaining('Request must contain a kbn-xsrf header.'),
+ });
+ expect(status).toBe(400);
+
+ ({ body, status } = await supertestWithoutAuth
.post('/api/encrypted_saved_objects/_rotate_key')
.set(internalReqHeader)
- .set(roleAuthc.apiKeyHeader);
- svlCommonApi.assertApiNotFound(body, status);
+ .set(roleAuthc.apiKeyHeader));
+ // expect a different, legitimate error when we use the internal header
+ // the config does not contain decryptionOnlyKeys, so when the API is
+ // called successfully, it will error for this reason, and not for an
+ // access or or missing header reason
+ expect(body).toEqual({
+ statusCode: 400,
+ error: 'Bad Request',
+ message: expect.stringContaining(
+ 'Kibana is not configured to support encryption key rotation. Update `kibana.yml` to include `xpack.encryptedSavedObjects.keyRotation.decryptionOnlyKeys` to rotate your encryption keys.'
+ ),
+ });
+ expect(status).toBe(400);
});
});
});
diff --git a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts
index e50e27c54fd01..44169d1e8f379 100644
--- a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts
+++ b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts
@@ -203,5 +203,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
it('has embedded console', async () => {
await testHasEmbeddedConsole(pageObjects);
});
+
+ describe('connectors enabled on serverless search', () => {
+ it('has all LLM connectors', async () => {
+ await pageObjects.searchPlayground.PlaygroundStartChatPage.expectOpenConnectorPagePlayground();
+ await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundLLMConnectorOptionsExists();
+ });
+ });
});
}