diff --git a/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts b/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts index 8b11387a1d0208..aab641367339ca 100644 --- a/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts @@ -6,89 +6,69 @@ * Side Public License, v 1. */ -/** - * Copied from src/core/server/elasticsearch/legacy/api_types.ts including its deprecation mentioned below - * TODO: Remove this and refactor the readPrivileges to utilize any newer client side ways rather than all this deprecated legacy stuff - */ -export interface LegacyCallAPIOptions { - /** - * Indicates whether `401 Unauthorized` errors returned from the Elasticsearch API - * should be wrapped into `Boom` error instances with properly set `WWW-Authenticate` - * header that could have been returned by the API itself. If API didn't specify that - * then `Basic realm="Authorization Required"` is used as `WWW-Authenticate`. - */ - wrap401Errors?: boolean; - /** - * A signal object that allows you to abort the request via an AbortController object. - */ - signal?: AbortSignal; -} - -type CallWithRequest, V> = ( - endpoint: string, - params: T, - options?: LegacyCallAPIOptions -) => Promise; +import { ElasticsearchClient } from '../elasticsearch_client'; export const readPrivileges = async ( - callWithRequest: CallWithRequest<{}, unknown>, + esClient: ElasticsearchClient, index: string ): Promise => { - return callWithRequest('transport.request', { - path: '/_security/user/_has_privileges', - method: 'POST', - body: { - cluster: [ - 'all', - 'create_snapshot', - 'manage', - 'manage_api_key', - 'manage_ccr', - 'manage_transform', - 'manage_ilm', - 'manage_index_templates', - 'manage_ingest_pipelines', - 'manage_ml', - 'manage_own_api_key', - 'manage_pipeline', - 'manage_rollup', - 'manage_saml', - 'manage_security', - 'manage_token', - 'manage_watcher', - 'monitor', - 'monitor_transform', - 'monitor_ml', - 'monitor_rollup', - 'monitor_watcher', - 'read_ccr', - 'read_ilm', - 'transport_client', - ], - index: [ - { - names: [index], - privileges: [ - 'all', - 'create', - 'create_doc', - 'create_index', - 'delete', - 'delete_index', - 'index', - 'manage', - 'maintenance', - 'manage_follow_index', - 'manage_ilm', - 'manage_leader_index', - 'monitor', - 'read', - 'read_cross_cluster', - 'view_index_metadata', - 'write', - ], - }, - ], - }, - }); + return ( + await esClient.transport.request({ + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + cluster: [ + 'all', + 'create_snapshot', + 'manage', + 'manage_api_key', + 'manage_ccr', + 'manage_transform', + 'manage_ilm', + 'manage_index_templates', + 'manage_ingest_pipelines', + 'manage_ml', + 'manage_own_api_key', + 'manage_pipeline', + 'manage_rollup', + 'manage_saml', + 'manage_security', + 'manage_token', + 'manage_watcher', + 'monitor', + 'monitor_transform', + 'monitor_ml', + 'monitor_rollup', + 'monitor_watcher', + 'read_ccr', + 'read_ilm', + 'transport_client', + ], + index: [ + { + names: [index], + privileges: [ + 'all', + 'create', + 'create_doc', + 'create_index', + 'delete', + 'delete_index', + 'index', + 'manage', + 'maintenance', + 'manage_follow_index', + 'manage_ilm', + 'manage_leader_index', + 'monitor', + 'read', + 'read_cross_cluster', + 'view_index_metadata', + 'write', + ], + }, + ], + }, + }) + ).body; }; diff --git a/x-pack/plugins/lists/server/routes/read_privileges_route.ts b/x-pack/plugins/lists/server/routes/read_privileges_route.ts index e0806a9f8f82ec..0fc72e6cc4341f 100644 --- a/x-pack/plugins/lists/server/routes/read_privileges_route.ts +++ b/x-pack/plugins/lists/server/routes/read_privileges_route.ts @@ -25,16 +25,10 @@ export const readPrivilegesRoute = (router: ListsPluginRouter): void => { async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client.asCurrentUser; const lists = getListClient(context); - const clusterPrivilegesLists = await readPrivileges( - clusterClient.callAsCurrentUser, - lists.getListIndex() - ); - const clusterPrivilegesListItems = await readPrivileges( - clusterClient.callAsCurrentUser, - lists.getListItemIndex() - ); + const clusterPrivilegesLists = await readPrivileges(esClient, lists.getListIndex()); + const clusterPrivilegesListItems = await readPrivileges(esClient, lists.getListItemIndex()); const privileges = merge( { listItems: clusterPrivilegesListItems, diff --git a/x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts b/x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts deleted file mode 100644 index 5ed745c3dbc90b..00000000000000 --- a/x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 { CreateDocumentResponse } from 'elasticsearch'; -import { LegacyAPICaller } from 'kibana/server'; - -import { LIST_INDEX } from '../../../common/constants.mock'; - -import { getShardMock } from './get_shard.mock'; - -export const getEmptyCreateDocumentResponseMock = (): CreateDocumentResponse => ({ - _id: 'elastic-id-123', - _index: LIST_INDEX, - _shards: getShardMock(), - _type: '', - _version: 1, - created: true, - result: '', -}); - -export const getCallClusterMock = ( - response: unknown = getEmptyCreateDocumentResponseMock() -): LegacyAPICaller => jest.fn().mockResolvedValue(response); - -export const getCallClusterMockMultiTimes = ( - responses: unknown[] = [getEmptyCreateDocumentResponseMock()] -): LegacyAPICaller => { - const returnJest = jest.fn(); - responses.forEach((response) => { - returnJest.mockResolvedValueOnce(response); - }); - return returnJest; -}; diff --git a/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts b/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts index 76ab48a8243db3..85d339970dc594 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts @@ -13,8 +13,6 @@ import { } from '../../../../../../src/plugins/data/common'; import { DocValueFields, Maybe } from '../common'; -export type BeatFieldsFactoryQueryType = 'beatFields'; - interface FieldInfo { category: string; description?: string; diff --git a/x-pack/plugins/security_solution/server/lib/compose/kibana.ts b/x-pack/plugins/security_solution/server/lib/compose/kibana.ts deleted file mode 100644 index 9be922ecf8db26..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/compose/kibana.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 { CoreSetup } from '../../../../../../src/core/server'; -import { SetupPlugins } from '../../plugin'; - -import { KibanaBackendFrameworkAdapter } from '../framework/kibana_framework_adapter'; - -import { ElasticsearchIndexFieldAdapter, IndexFields } from '../index_fields'; - -import { ElasticsearchSourceStatusAdapter, SourceStatus } from '../source_status'; -import { ConfigurationSourcesAdapter, Sources } from '../sources'; -import { AppBackendLibs, AppDomainLibs } from '../types'; -import { note, pinnedEvent, timeline } from '../timeline/saved_object'; -import { EndpointAppContext } from '../../endpoint/types'; - -export function compose( - core: CoreSetup, - plugins: SetupPlugins, - endpointContext: EndpointAppContext -): AppBackendLibs { - const framework = new KibanaBackendFrameworkAdapter(); - const sources = new Sources(new ConfigurationSourcesAdapter()); - const sourceStatus = new SourceStatus(new ElasticsearchSourceStatusAdapter(framework)); - - const domainLibs: AppDomainLibs = { - fields: new IndexFields(new ElasticsearchIndexFieldAdapter()), - }; - - const libs: AppBackendLibs = { - framework, - sourceStatus, - sources, - ...domainLibs, - timeline, - note, - pinnedEvent, - }; - - return libs; -} diff --git a/x-pack/plugins/security_solution/server/lib/configuration/adapter_types.ts b/x-pack/plugins/security_solution/server/lib/configuration/adapter_types.ts deleted file mode 100644 index d962cacbb67129..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/configuration/adapter_types.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface ConfigurationAdapter { - get(): Promise; -} diff --git a/x-pack/plugins/security_solution/server/lib/configuration/index.ts b/x-pack/plugins/security_solution/server/lib/configuration/index.ts deleted file mode 100644 index 5d7c09c54b8c14..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/configuration/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * 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 * from './adapter_types'; diff --git a/x-pack/plugins/security_solution/server/lib/configuration/inmemory_configuration_adapter.ts b/x-pack/plugins/security_solution/server/lib/configuration/inmemory_configuration_adapter.ts deleted file mode 100644 index e0418a6ed061a4..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/configuration/inmemory_configuration_adapter.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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 { ConfigurationAdapter } from './adapter_types'; - -export class InmemoryConfigurationAdapter - implements ConfigurationAdapter { - constructor(private readonly configuration: Configuration) {} - - public async get() { - return this.configuration; - } -} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/privileges/read_privileges.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/privileges/read_privileges.ts deleted file mode 100644 index bb0c5456c5f401..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/privileges/read_privileges.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 { CallWithRequest } from '../types'; - -export const readPrivileges = async ( - callWithRequest: CallWithRequest<{}, unknown>, - index: string -): Promise => { - return callWithRequest('transport.request', { - path: '/_security/user/_has_privileges', - method: 'POST', - body: { - cluster: [ - 'all', - 'create_snapshot', - 'manage', - 'manage_api_key', - 'manage_ccr', - 'manage_transform', - 'manage_ilm', - 'manage_index_templates', - 'manage_ingest_pipelines', - 'manage_ml', - 'manage_own_api_key', - 'manage_pipeline', - 'manage_rollup', - 'manage_saml', - 'manage_security', - 'manage_token', - 'manage_watcher', - 'monitor', - 'monitor_transform', - 'monitor_ml', - 'monitor_rollup', - 'monitor_watcher', - 'read_ccr', - 'read_ilm', - 'transport_client', - ], - index: [ - { - names: [index], - privileges: [ - 'all', - 'create', - 'create_doc', - 'create_index', - 'delete', - 'delete_index', - 'index', - 'manage', - 'maintenance', - 'manage_follow_index', - 'manage_ilm', - 'manage_leader_index', - 'monitor', - 'read', - 'read_cross_cluster', - 'view_index_metadata', - 'write', - ], - }, - ], - }, - }); -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts index 533b3f86728f1d..2e33200ee73908 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts @@ -17,16 +17,34 @@ import { siemMock } from '../../../../mocks'; const createMockClients = () => ({ alertsClient: alertsClientMock.create(), - clusterClient: elasticsearchServiceMock.createLegacyScopedClusterClient(), licensing: { license: licensingMock.createLicenseMock() }, - newClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + clusterClient: elasticsearchServiceMock.createScopedClusterClient(), savedObjectsClient: savedObjectsClientMock.create(), appClient: siemMock.createClient(), }); +/** + * Adds mocking to the interface so we don't have to cast everywhere + */ +type SecuritySolutionRequestHandlerContextMock = SecuritySolutionRequestHandlerContext & { + core: { + elasticsearch: { + client: { + asCurrentUser: { + updateByQuery: jest.Mock; + search: jest.Mock; + transport: { + request: jest.Mock; + }; + }; + }; + }; + }; +}; + const createRequestContextMock = ( clients: ReturnType = createMockClients() -) => { +): SecuritySolutionRequestHandlerContextMock => { const coreContext = coreMock.createRequestHandlerContext(); return ({ alerting: { getAlertsClient: jest.fn(() => clients.alertsClient) }, @@ -34,14 +52,13 @@ const createRequestContextMock = ( ...coreContext, elasticsearch: { ...coreContext.elasticsearch, - client: clients.newClusterClient, - legacy: { ...coreContext.elasticsearch.legacy, client: clients.clusterClient }, + client: clients.clusterClient, }, savedObjects: { client: clients.savedObjectsClient }, }, licensing: clients.licensing, securitySolution: { getAppClient: jest.fn(() => clients.appClient) }, - } as unknown) as SecuritySolutionRequestHandlerContext; + } as unknown) as SecuritySolutionRequestHandlerContextMock; }; const createTools = () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 3942d1637fedd1..8959c2b89d2b6f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -20,7 +20,6 @@ import { DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL, DETECTION_ENGINE_RULES_BULK_ACTION, } from '../../../../../common/constants'; -import { ShardsResponse } from '../../../types'; import { RuleAlertType, IRuleSavedAttributesSavedObjectAttributes, @@ -50,6 +49,7 @@ export const typicalSetStatusSignalByQueryPayload = (): SetSignalsStatusSchemaDe }); export const typicalSignalsQuery = (): QuerySignalsSchemaDecoded => ({ + aggs: {}, query: { match_all: {} }, }); @@ -608,14 +608,6 @@ export const getSuccessfulSignalUpdateResponse = () => ({ failures: [], }); -export const getIndexName = () => 'index-name'; -export const getEmptyIndex = (): { _shards: Partial } => ({ - _shards: { total: 0 }, -}); -export const getNonEmptyIndex = (): { _shards: Partial } => ({ - _shards: { total: 1 }, -}); - export const getNotificationResult = (): RuleNotificationAlertType => ({ id: '200dbf2f-b269-4bf9-aa85-11ba32ba73ba', name: 'Notification for Rule Test', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts index 2efb65c4a49a24..b79bdc857a171c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts @@ -8,16 +8,21 @@ import { readPrivilegesRoute } from './read_privileges_route'; import { serverMock, requestContextMock } from '../__mocks__'; import { getPrivilegeRequest, getMockPrivilegesResult } from '../__mocks__/request_responses'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; describe('read_privileges route', () => { let server: ReturnType; - let { clients, context } = requestContextMock.createTools(); + let { context } = requestContextMock.createTools(); beforeEach(() => { server = serverMock.create(); - ({ clients, context } = requestContextMock.createTools()); + ({ context } = requestContextMock.createTools()); + + context.core.elasticsearch.client.asCurrentUser.transport.request.mockResolvedValue({ + body: getMockPrivilegesResult(), + }); - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getMockPrivilegesResult()); readPrivilegesRoute(server.router, true); }); @@ -60,9 +65,9 @@ describe('read_privileges route', () => { }); test('returns 500 when bad response from cluster', async () => { - clients.clusterClient.callAsCurrentUser.mockImplementation(() => { - throw new Error('Test error'); - }); + context.core.elasticsearch.client.asCurrentUser.transport.request.mockResolvedValue( + elasticsearchClientMock.createErrorTransportRequestPromise(new Error('Test error')) + ); const response = await server.inject( getPrivilegeRequest({ auth: { isAuthenticated: false } }), context diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.ts index 04fd2aeaebb2d4..2c86b5e2f03262 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.ts @@ -7,13 +7,11 @@ import { merge } from 'lodash/fp'; -import { transformError } from '@kbn/securitysolution-es-utils'; +import { readPrivileges, transformError } from '@kbn/securitysolution-es-utils'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_PRIVILEGES_URL } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; -import { readPrivileges } from '../../privileges/read_privileges'; - export const readPrivilegesRoute = ( router: SecuritySolutionPluginRouter, hasEncryptionKey: boolean @@ -30,7 +28,7 @@ export const readPrivilegesRoute = ( const siemResponse = buildSiemResponse(response); try { - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client.asCurrentUser; const siemClient = context.securitySolution?.getAppClient(); if (!siemClient) { @@ -38,7 +36,7 @@ export const readPrivilegesRoute = ( } const index = siemClient.getSignalsIndex(); - const clusterPrivileges = await readPrivileges(clusterClient.callAsCurrentUser, index); + const clusterPrivileges = await readPrivileges(esClient, index); const privileges = merge(clusterPrivileges, { is_authenticated: request.auth.isAuthenticated ?? false, has_encryption_key: hasEncryptionKey, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts index 026820a8f2ff76..8987bc9b6f0c0e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts @@ -9,7 +9,6 @@ import { getEmptyFindResult, addPrepackagedRulesRequest, getFindResultWithSingleHit, - getNonEmptyIndex, } from '../__mocks__/request_responses'; import { requestContextMock, serverMock, createMockConfig, mockGetCurrentUser } from '../__mocks__'; import { AddPrepackagedRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; @@ -90,7 +89,6 @@ describe('add_prepackaged_rules_route', () => { mockExceptionsClient = listMock.getExceptionListClient(); - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getNonEmptyIndex()); clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); (installPrepackagedTimelines as jest.Mock).mockReset(); @@ -102,8 +100,7 @@ describe('add_prepackaged_rules_route', () => { errors: [], }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) ); addPrepackedRulesRoute(server.router, createMockConfig(), securitySetup); @@ -131,8 +128,7 @@ describe('add_prepackaged_rules_route', () => { test('it returns a 400 if the index does not exist', async () => { const request = addPrepackagedRulesRequest(); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValueOnce( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) ); const response = await server.inject(request, context); @@ -187,8 +183,7 @@ describe('add_prepackaged_rules_route', () => { }); test('catches errors if payloads cause errors to be thrown', async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createErrorTransportRequestPromise(new Error('Test error')) ); const request = addPrepackagedRulesRequest(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts index 311e2fcc41a0b8..bbb753f1f62de2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts @@ -10,7 +10,6 @@ import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../mach import { buildMlAuthz } from '../../../machine_learning/authz'; import { getReadBulkRequest, - getNonEmptyIndex, getFindResultWithSingleHit, getEmptyFindResult, getAlertMock, @@ -35,12 +34,10 @@ describe('create_rules_bulk', () => { ({ clients, context } = requestContextMock.createTools()); ml = mlServicesMock.createSetupContract(); - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getNonEmptyIndex()); // index exists clients.alertsClient.find.mockResolvedValue(getEmptyFindResult()); // no existing rules clients.alertsClient.create.mockResolvedValue(getAlertMock(getQueryRuleParams())); // successful creation - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) ); createRulesBulkRoute(server.router, ml); @@ -90,8 +87,7 @@ describe('create_rules_bulk', () => { }); it('returns an error object if the index does not exist', async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValueOnce( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) ); const response = await server.inject(getReadBulkRequest(), context); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts index b04f178363f998..6b0b01a9a9de90 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts @@ -11,7 +11,6 @@ import { getAlertMock, getCreateRequest, getFindResultStatus, - getNonEmptyIndex, getFindResultWithSingleHit, createMlRuleRequest, } from '../__mocks__/request_responses'; @@ -37,13 +36,11 @@ describe('create_rules', () => { ({ clients, context } = requestContextMock.createTools()); ml = mlServicesMock.createSetupContract(); - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getNonEmptyIndex()); // index exists clients.alertsClient.find.mockResolvedValue(getEmptyFindResult()); // no current rules clients.alertsClient.create.mockResolvedValue(getAlertMock(getQueryRuleParams())); // creation succeeds clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); // needed to transform - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) ); createRulesRoute(server.router, ml); @@ -108,8 +105,7 @@ describe('create_rules', () => { describe('unhappy paths', () => { test('it returns a 400 if the index does not exist', async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValueOnce( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) ); const response = await server.inject(getCreateRequest(), context); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts index 993d9300e414f4..4b78586ba739ba 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -26,7 +26,7 @@ import { convertCreateAPIToInternalSchema } from '../../schemas/rule_converters' export const createRulesRoute = ( router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml'], - ruleDataClient?: RuleDataClient | null + ruleDataClient?: RuleDataClient | null // TODO: Use this for RAC (otherwise delete it) ): void => { router.post( { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts index 3c8321ee8eb9a5..f88da36db4491c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts @@ -11,7 +11,6 @@ import { getEmptyFindResult, getFindResultWithSingleHit, getPrepackagedRulesStatusRequest, - getNonEmptyIndex, } from '../__mocks__/request_responses'; import { requestContextMock, serverMock, createMockConfig } from '../__mocks__'; import { SecurityPluginSetup } from '../../../../../../security/server'; @@ -74,7 +73,6 @@ describe('get_prepackaged_rule_status_route', () => { authz: {}, } as unknown) as SecurityPluginSetup; - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getNonEmptyIndex()); clients.alertsClient.find.mockResolvedValue(getEmptyFindResult()); getPrepackagedRulesStatusRoute(server.router, createMockConfig(), securitySetup); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts index 0a680d1b0d1c11..ab9e6983590c9e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts @@ -12,7 +12,6 @@ import { getEmptyFindResult, getAlertMock, getFindResultWithSingleHit, - getNonEmptyIndex, } from '../__mocks__/request_responses'; import { createMockConfig, requestContextMock, serverMock, requestMock } from '../__mocks__'; import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; @@ -45,11 +44,9 @@ describe('import_rules_route', () => { request = getImportRulesRequest(hapiStream); ml = mlServicesMock.createSetupContract(); - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getNonEmptyIndex()); // index exists clients.alertsClient.find.mockResolvedValue(getEmptyFindResult()); // no extant rules - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) ); importRulesRoute(server.router, config, ml); @@ -130,8 +127,7 @@ describe('import_rules_route', () => { test('returns an error if the index does not exist', async () => { clients.appClient.getSignalsIndex.mockReturnValue('mockSignalsIndex'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValueOnce( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) ); const response = await server.inject(request, context); @@ -144,8 +140,7 @@ describe('import_rules_route', () => { }); test('returns an error when cluster throws error', async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createErrorTransportRequestPromise({ body: new Error('Test error'), }) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals.test.ts index 9a9f8e949fab7f..f6abfc9ebe3d16 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals.test.ts @@ -16,17 +16,21 @@ import { } from '../__mocks__/request_responses'; import { requestContextMock, serverMock, requestMock } from '../__mocks__'; import { setSignalsStatusRoute } from './open_close_signals_route'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; describe('set signal status', () => { let server: ReturnType; - let { clients, context } = requestContextMock.createTools(); + let { context } = requestContextMock.createTools(); beforeEach(() => { server = serverMock.create(); - ({ clients, context } = requestContextMock.createTools()); - - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getSuccessfulSignalUpdateResponse()); - + ({ context } = requestContextMock.createTools()); + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise( + getSuccessfulSignalUpdateResponse() + ) + ); setSignalsStatusRoute(server.router); }); @@ -52,10 +56,10 @@ describe('set signal status', () => { expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); }); - test('catches error if callAsCurrentUser throws error', async () => { - clients.clusterClient.callAsCurrentUser.mockImplementation(async () => { - throw new Error('Test error'); - }); + test('catches error if asCurrentUser throws error', async () => { + context.core.elasticsearch.client.asCurrentUser.updateByQuery.mockResolvedValue( + elasticsearchClientMock.createErrorTransportRequestPromise(new Error('Test error')) + ); const response = await server.inject(getSetSignalStatusByQueryRequest(), context); expect(response.status).toEqual(500); expect(response.body).toEqual({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts index fd001595fb9c75..bf21f9de037f4a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts @@ -32,7 +32,7 @@ export const setSignalsStatusRoute = (router: SecuritySolutionPluginRouter) => { }, async (context, request, response) => { const { conflicts, signal_ids: signalIds, query, status } = request.body; - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client.asCurrentUser; const siemClient = context.securitySolution?.getAppClient(); const siemResponse = buildSiemResponse(response); const validationErrors = setSignalStatusValidateTypeDependents(request.body); @@ -57,10 +57,13 @@ export const setSignalsStatusRoute = (router: SecuritySolutionPluginRouter) => { }; } try { - const result = await clusterClient.callAsCurrentUser('updateByQuery', { + const { body } = await esClient.updateByQuery({ index: siemClient.getSignalsIndex(), conflicts: conflicts ?? 'abort', - refresh: 'wait_for', + // https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update-by-query.html#_refreshing_shards_2 + // Note: Before we tried to use "refresh: wait_for" but I do not think that was available and instead it defaulted to "refresh: true" + // but the tests do not pass with "refresh: false". If at some point a "refresh: wait_for" is implemented, we should use that instead. + refresh: true, body: { script: { source: `ctx._source.signal.status = '${status}'`, @@ -68,9 +71,9 @@ export const setSignalsStatusRoute = (router: SecuritySolutionPluginRouter) => { }, query: queryObject, }, - ignoreUnavailable: true, + ignore_unavailable: true, }); - return response.ok({ body: result }); + return response.ok({ body }); } catch (err) { // error while getting or updating signal with id: id in signal index .siem-signals const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts index d6b998e3142349..dd181476a48904 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts @@ -16,16 +16,20 @@ import { } from '../__mocks__/request_responses'; import { requestContextMock, serverMock, requestMock, createMockConfig } from '../__mocks__'; import { querySignalsRoute } from './query_signals_route'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; describe('query for signal', () => { let server: ReturnType; - let { clients, context } = requestContextMock.createTools(); + let { context } = requestContextMock.createTools(); beforeEach(() => { server = serverMock.create(); - ({ clients, context } = requestContextMock.createTools()); + ({ context } = requestContextMock.createTools()); - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getEmptySignalsResponse()); + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(getEmptySignalsResponse()) + ); querySignalsRoute(server.router, createMockConfig()); }); @@ -35,9 +39,10 @@ describe('query for signal', () => { const response = await server.inject(getSignalsQueryRequest(), context); expect(response.status).toEqual(200); - expect(clients.clusterClient.callAsCurrentUser).toHaveBeenCalledWith( - 'search', - expect.objectContaining({ body: typicalSignalsQuery() }) + expect(context.core.elasticsearch.client.asCurrentUser.search).toHaveBeenCalledWith( + expect.objectContaining({ + body: typicalSignalsQuery(), + }) ); }); @@ -45,9 +50,8 @@ describe('query for signal', () => { const response = await server.inject(getSignalsAggsQueryRequest(), context); expect(response.status).toEqual(200); - expect(clients.clusterClient.callAsCurrentUser).toHaveBeenCalledWith( - 'search', - expect.objectContaining({ body: typicalSignalsQueryAggs() }) + expect(context.core.elasticsearch.client.asCurrentUser.search).toHaveBeenCalledWith( + expect.objectContaining({ body: typicalSignalsQueryAggs(), ignore_unavailable: true }) ); }); @@ -55,8 +59,7 @@ describe('query for signal', () => { const response = await server.inject(getSignalsAggsAndQueryRequest(), context); expect(response.status).toEqual(200); - expect(clients.clusterClient.callAsCurrentUser).toHaveBeenCalledWith( - 'search', + expect(context.core.elasticsearch.client.asCurrentUser.search).toHaveBeenCalledWith( expect.objectContaining({ body: { ...typicalSignalsQuery(), @@ -67,9 +70,9 @@ describe('query for signal', () => { }); test('catches error if query throws error', async () => { - clients.clusterClient.callAsCurrentUser.mockImplementation(async () => { - throw new Error('Test error'); - }); + context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createErrorTransportRequestPromise(new Error('Test error')) + ); const response = await server.inject(getSignalsAggsQueryRequest(), context); expect(response.status).toEqual(500); expect(response.body).toEqual({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts index 770c1a5da344f6..279a824426cec0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -50,19 +50,26 @@ export const querySignalsRoute = (router: SecuritySolutionPluginRouter, config: body: '"value" must have at least 1 children', }); } - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client.asCurrentUser; const siemClient = context.securitySolution!.getAppClient(); // TODO: Once we are past experimental phase this code should be removed const { ruleRegistryEnabled } = parseExperimentalConfigValue(config.enableExperimental); try { - const result = await clusterClient.callAsCurrentUser('search', { + const { body } = await esClient.search({ index: ruleRegistryEnabled ? DEFAULT_ALERTS_INDEX : siemClient.getSignalsIndex(), - body: { query, aggs, _source, track_total_hits, size }, - ignoreUnavailable: true, + body: { + query, + // Note: I use a spread operator to please TypeScript with aggs: { ...aggs } + aggs: { ...aggs }, + _source, + track_total_hits, + size, + }, + ignore_unavailable: true, }); - return response.ok({ body: result }); + return response.ok({ body }); } catch (err) { // error while getting or updating signal with id: id in signal index .siem-signals const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts index 1b80a9b6b02e2c..9eb160ed2da560 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts @@ -52,7 +52,6 @@ import { EventCategoryOverrideOrUndefined, } from '../../../common/detection_engine/schemas/common/schemas'; -import { LegacyCallAPIOptions } from '../../../../../../src/core/server'; import { Filter } from '../../../../../../src/plugins/data/server'; import { AlertTypeParams } from '../../../../alerting/common'; @@ -104,11 +103,4 @@ export interface RuleTypeParams extends AlertTypeParams { itemsPerSearch?: ItemsPerSearchOrUndefined; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type CallWithRequest, V> = ( - endpoint: string, - params: T, - options?: LegacyCallAPIOptions -) => Promise; - export type RefreshTypes = false | 'wait_for'; diff --git a/x-pack/plugins/security_solution/server/lib/ecs_fields/extend_map.test.ts b/x-pack/plugins/security_solution/server/lib/ecs_fields/extend_map.test.ts deleted file mode 100644 index e27b15f021257c..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/ecs_fields/extend_map.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 { extendMap } from './extend_map'; - -describe('ecs_fields test', () => { - describe('extendMap', () => { - test('it should extend a record', () => { - const osFieldsMap: Readonly> = { - 'os.platform': 'os.platform', - 'os.full': 'os.full', - 'os.family': 'os.family', - 'os.version': 'os.version', - 'os.kernel': 'os.kernel', - }; - const expected: Record = { - 'host.os.family': 'host.os.family', - 'host.os.full': 'host.os.full', - 'host.os.kernel': 'host.os.kernel', - 'host.os.platform': 'host.os.platform', - 'host.os.version': 'host.os.version', - }; - expect(extendMap('host', osFieldsMap)).toEqual(expected); - }); - - test('it should extend a sample hosts record', () => { - const hostMap: Record = { - 'host.id': 'host.id', - 'host.ip': 'host.ip', - 'host.name': 'host.name', - }; - const osFieldsMap: Readonly> = { - 'os.platform': 'os.platform', - 'os.full': 'os.full', - 'os.family': 'os.family', - 'os.version': 'os.version', - 'os.kernel': 'os.kernel', - }; - const expected: Record = { - 'host.id': 'host.id', - 'host.ip': 'host.ip', - 'host.name': 'host.name', - 'host.os.family': 'host.os.family', - 'host.os.full': 'host.os.full', - 'host.os.kernel': 'host.os.kernel', - 'host.os.platform': 'host.os.platform', - 'host.os.version': 'host.os.version', - }; - const output = { ...hostMap, ...extendMap('host', osFieldsMap) }; - expect(output).toEqual(expected); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/ecs_fields/extend_map.ts b/x-pack/plugins/security_solution/server/lib/ecs_fields/extend_map.ts deleted file mode 100644 index 184e6b4f325665..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/ecs_fields/extend_map.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const extendMap = ( - path: string, - map: Readonly> -): Readonly> => - Object.entries(map).reduce>((accum, [key, value]) => { - accum[`${path}.${key}`] = `${path}.${value}`; - return accum; - }, {}); diff --git a/x-pack/plugins/security_solution/server/lib/ecs_fields/index.ts b/x-pack/plugins/security_solution/server/lib/ecs_fields/index.ts deleted file mode 100644 index 7e9e4e8cd37bd3..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/ecs_fields/index.ts +++ /dev/null @@ -1,361 +0,0 @@ -/* - * 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 { extendMap } from './extend_map'; - -export const auditdMap: Readonly> = { - 'auditd.result': 'auditd.result', - 'auditd.session': 'auditd.session', - 'auditd.data.acct': 'auditd.data.acct', - 'auditd.data.terminal': 'auditd.data.terminal', - 'auditd.data.op': 'auditd.data.op', - 'auditd.summary.actor.primary': 'auditd.summary.actor.primary', - 'auditd.summary.actor.secondary': 'auditd.summary.actor.secondary', - 'auditd.summary.object.primary': 'auditd.summary.object.primary', - 'auditd.summary.object.secondary': 'auditd.summary.object.secondary', - 'auditd.summary.object.type': 'auditd.summary.object.type', - 'auditd.summary.how': 'auditd.summary.how', - 'auditd.summary.message_type': 'auditd.summary.message_type', - 'auditd.summary.sequence': 'auditd.summary.sequence', -}; - -export const cloudFieldsMap: Readonly> = { - 'cloud.account.id': 'cloud.account.id', - 'cloud.availability_zone': 'cloud.availability_zone', - 'cloud.instance.id': 'cloud.instance.id', - 'cloud.instance.name': 'cloud.instance.name', - 'cloud.machine.type': 'cloud.machine.type', - 'cloud.provider': 'cloud.provider', - 'cloud.region': 'cloud.region', -}; - -export const fileMap: Readonly> = { - 'file.name': 'file.name', - 'file.path': 'file.path', - 'file.target_path': 'file.target_path', - 'file.extension': 'file.extension', - 'file.type': 'file.type', - 'file.device': 'file.device', - 'file.inode': 'file.inode', - 'file.uid': 'file.uid', - 'file.owner': 'file.owner', - 'file.gid': 'file.gid', - 'file.group': 'file.group', - 'file.mode': 'file.mode', - 'file.size': 'file.size', - 'file.mtime': 'file.mtime', - 'file.ctime': 'file.ctime', -}; - -export const osFieldsMap: Readonly> = { - 'os.platform': 'os.platform', - 'os.name': 'os.name', - 'os.full': 'os.full', - 'os.family': 'os.family', - 'os.version': 'os.version', - 'os.kernel': 'os.kernel', -}; - -export const hostFieldsMap: Readonly> = { - 'host.architecture': 'host.architecture', - 'host.id': 'host.id', - 'host.ip': 'host.ip', - 'host.mac': 'host.mac', - 'host.name': 'host.name', - ...extendMap('host', osFieldsMap), -}; - -export const processFieldsMap: Readonly> = { - 'process.hash.md5': 'process.hash.md5', - 'process.hash.sha1': 'process.hash.sha1', - 'process.hash.sha256': 'process.hash.sha256', - 'process.pid': 'process.pid', - 'process.name': 'process.name', - 'process.ppid': 'process.ppid', - 'process.args': 'process.args', - 'process.entity_id': 'process.entity_id', - 'process.executable': 'process.executable', - 'process.title': 'process.title', - 'process.thread': 'process.thread', - 'process.working_directory': 'process.working_directory', -}; - -export const agentFieldsMap: Readonly> = { - 'agent.type': 'agent.type', - 'agent.id': 'agent.id', -}; - -export const userFieldsMap: Readonly> = { - 'user.domain': 'user.domain', - 'user.id': 'user.id', - 'user.name': 'user.name', - // NOTE: This field is not tested and available from ECS. Please remove this tag once it is - 'user.full_name': 'user.full_name', - // NOTE: This field is not tested and available from ECS. Please remove this tag once it is - 'user.email': 'user.email', - // NOTE: This field is not tested and available from ECS. Please remove this tag once it is - 'user.hash': 'user.hash', - // NOTE: This field is not tested and available from ECS. Please remove this tag once it is - 'user.group': 'user.group', -}; - -export const winlogFieldsMap: Readonly> = { - 'winlog.event_id': 'winlog.event_id', -}; - -export const suricataFieldsMap: Readonly> = { - 'suricata.eve.flow_id': 'suricata.eve.flow_id', - 'suricata.eve.proto': 'suricata.eve.proto', - 'suricata.eve.alert.signature': 'suricata.eve.alert.signature', - 'suricata.eve.alert.signature_id': 'suricata.eve.alert.signature_id', -}; - -export const tlsFieldsMap: Readonly> = { - 'tls.client_certificate.fingerprint.sha1': 'tls.client_certificate.fingerprint.sha1', - 'tls.fingerprints.ja3.hash': 'tls.fingerprints.ja3.hash', - 'tls.server_certificate.fingerprint.sha1': 'tls.server_certificate.fingerprint.sha1', -}; - -export const urlFieldsMap: Readonly> = { - 'url.original': 'url.original', - 'url.domain': 'url.domain', - 'user.username': 'user.username', - 'user.password': 'user.password', -}; - -export const httpFieldsMap: Readonly> = { - 'http.version': 'http.version', - 'http.request': 'http.request', - 'http.request.method': 'http.request.method', - 'http.request.body.bytes': 'http.request.body.bytes', - 'http.request.body.content': 'http.request.body.content', - 'http.request.referrer': 'http.request.referrer', - 'http.response.status_code': 'http.response.status_code', - 'http.response.body': 'http.response.body', - 'http.response.body.bytes': 'http.response.body.bytes', - 'http.response.body.content': 'http.response.body.content', -}; - -export const zeekFieldsMap: Readonly> = { - 'zeek.session_id': 'zeek.session_id', - 'zeek.connection.local_resp': 'zeek.connection.local_resp', - 'zeek.connection.local_orig': 'zeek.connection.local_orig', - 'zeek.connection.missed_bytes': 'zeek.connection.missed_bytes', - 'zeek.connection.state': 'zeek.connection.state', - 'zeek.connection.history': 'zeek.connection.history', - 'zeek.notice.suppress_for': 'zeek.notice.suppress_for', - 'zeek.notice.msg': 'zeek.notice.msg', - 'zeek.notice.note': 'zeek.notice.note', - 'zeek.notice.sub': 'zeek.notice.sub', - 'zeek.notice.dst': 'zeek.notice.dst', - 'zeek.notice.dropped': 'zeek.notice.dropped', - 'zeek.notice.peer_descr': 'zeek.notice.peer_descr', - 'zeek.dns.AA': 'zeek.dns.AA', - 'zeek.dns.qclass_name': 'zeek.dns.qclass_name', - 'zeek.dns.RD': 'zeek.dns.RD', - 'zeek.dns.qtype_name': 'zeek.dns.qtype_name', - 'zeek.dns.qtype': 'zeek.dns.qtype', - 'zeek.dns.query': 'zeek.dns.query', - 'zeek.dns.trans_id': 'zeek.dns.trans_id', - 'zeek.dns.qclass': 'zeek.dns.qclass', - 'zeek.dns.RA': 'zeek.dns.RA', - 'zeek.dns.TC': 'zeek.dns.TC', - 'zeek.http.resp_mime_types': 'zeek.http.resp_mime_types', - 'zeek.http.trans_depth': 'zeek.http.trans_depth', - 'zeek.http.status_msg': 'zeek.http.status_msg', - 'zeek.http.resp_fuids': 'zeek.http.resp_fuids', - 'zeek.http.tags': 'zeek.http.tags', - 'zeek.files.session_ids': 'zeek.files.session_ids', - 'zeek.files.timedout': 'zeek.files.timedout', - 'zeek.files.local_orig': 'zeek.files.local_orig', - 'zeek.files.tx_host': 'zeek.files.tx_host', - 'zeek.files.source': 'zeek.files.source', - 'zeek.files.is_orig': 'zeek.files.is_orig', - 'zeek.files.overflow_bytes': 'zeek.files.overflow_bytes', - 'zeek.files.sha1': 'zeek.files.sha1', - 'zeek.files.duration': 'zeek.files.duration', - 'zeek.files.depth': 'zeek.files.depth', - 'zeek.files.analyzers': 'zeek.files.analyzers', - 'zeek.files.mime_type': 'zeek.files.mime_type', - 'zeek.files.rx_host': 'zeek.files.rx_host', - 'zeek.files.total_bytes': 'zeek.files.total_bytes', - 'zeek.files.fuid': 'zeek.files.fuid', - 'zeek.files.seen_bytes': 'zeek.files.seen_bytes', - 'zeek.files.missing_bytes': 'zeek.files.missing_bytes', - 'zeek.files.md5': 'zeek.files.md5', - 'zeek.ssl.cipher': 'zeek.ssl.cipher', - 'zeek.ssl.established': 'zeek.ssl.established', - 'zeek.ssl.resumed': 'zeek.ssl.resumed', - 'zeek.ssl.version': 'zeek.ssl.version', -}; - -export const sourceFieldsMap: Readonly> = { - 'source.bytes': 'source.bytes', - 'source.ip': 'source.ip', - 'source.packets': 'source.packets', - 'source.port': 'source.port', - 'source.domain': 'source.domain', - 'source.geo.continent_name': 'source.geo.continent_name', - 'source.geo.country_name': 'source.geo.country_name', - 'source.geo.country_iso_code': 'source.geo.country_iso_code', - 'source.geo.city_name': 'source.geo.city_name', - 'source.geo.region_iso_code': 'source.geo.region_iso_code', - 'source.geo.region_name': 'source.geo.region_name', -}; - -export const destinationFieldsMap: Readonly> = { - 'destination.bytes': 'destination.bytes', - 'destination.ip': 'destination.ip', - 'destination.packets': 'destination.packets', - 'destination.port': 'destination.port', - 'destination.domain': 'destination.domain', - 'destination.geo.continent_name': 'destination.geo.continent_name', - 'destination.geo.country_name': 'destination.geo.country_name', - 'destination.geo.country_iso_code': 'destination.geo.country_iso_code', - 'destination.geo.city_name': 'destination.geo.city_name', - 'destination.geo.region_iso_code': 'destination.geo.region_iso_code', - 'destination.geo.region_name': 'destination.geo.region_name', -}; - -export const networkFieldsMap: Readonly> = { - 'network.bytes': 'network.bytes', - 'network.community_id': 'network.community_id', - 'network.direction': 'network.direction', - 'network.packets': 'network.packets', - 'network.protocol': 'network.protocol', - 'network.transport': 'network.transport', -}; - -export const geoFieldsMap: Readonly> = { - 'geo.region_name': 'destination.geo.region_name', - 'geo.country_iso_code': 'destination.geo.country_iso_code', -}; - -export const dnsFieldsMap: Readonly> = { - 'dns.question.name': 'dns.question.name', - 'dns.question.type': 'dns.question.type', - 'dns.resolved_ip': 'dns.resolved_ip', - 'dns.response_code': 'dns.response_code', -}; - -export const endgameFieldsMap: Readonly> = { - 'endgame.exit_code': 'endgame.exit_code', - 'endgame.file_name': 'endgame.file_name', - 'endgame.file_path': 'endgame.file_path', - 'endgame.logon_type': 'endgame.logon_type', - 'endgame.parent_process_name': 'endgame.parent_process_name', - 'endgame.pid': 'endgame.pid', - 'endgame.process_name': 'endgame.process_name', - 'endgame.subject_domain_name': 'endgame.subject_domain_name', - 'endgame.subject_logon_id': 'endgame.subject_logon_id', - 'endgame.subject_user_name': 'endgame.subject_user_name', - 'endgame.target_domain_name': 'endgame.target_domain_name', - 'endgame.target_logon_id': 'endgame.target_logon_id', - 'endgame.target_user_name': 'endgame.target_user_name', -}; - -export const eventBaseFieldsMap: Readonly> = { - 'event.action': 'event.action', - 'event.category': 'event.category', - 'event.code': 'event.code', - 'event.created': 'event.created', - 'event.dataset': 'event.dataset', - 'event.duration': 'event.duration', - 'event.end': 'event.end', - 'event.hash': 'event.hash', - 'event.id': 'event.id', - 'event.kind': 'event.kind', - 'event.module': 'event.module', - 'event.original': 'event.original', - 'event.outcome': 'event.outcome', - 'event.risk_score': 'event.risk_score', - 'event.risk_score_norm': 'event.risk_score_norm', - 'event.severity': 'event.severity', - 'event.start': 'event.start', - 'event.timezone': 'event.timezone', - 'event.type': 'event.type', -}; - -export const systemFieldsMap: Readonly> = { - 'system.audit.package.arch': 'system.audit.package.arch', - 'system.audit.package.entity_id': 'system.audit.package.entity_id', - 'system.audit.package.name': 'system.audit.package.name', - 'system.audit.package.size': 'system.audit.package.size', - 'system.audit.package.summary': 'system.audit.package.summary', - 'system.audit.package.version': 'system.audit.package.version', - 'system.auth.ssh.signature': 'system.auth.ssh.signature', - 'system.auth.ssh.method': 'system.auth.ssh.method', -}; - -export const signalFieldsMap: Readonly> = { - 'signal.original_time': 'signal.original_time', - 'signal.rule.id': 'signal.rule.id', - 'signal.rule.saved_id': 'signal.rule.saved_id', - 'signal.rule.timeline_id': 'signal.rule.timeline_id', - 'signal.rule.timeline_title': 'signal.rule.timeline_title', - 'signal.rule.output_index': 'signal.rule.output_index', - 'signal.rule.from': 'signal.rule.from', - 'signal.rule.index': 'signal.rule.index', - 'signal.rule.language': 'signal.rule.language', - 'signal.rule.query': 'signal.rule.query', - 'signal.rule.to': 'signal.rule.to', - 'signal.rule.filters': 'signal.rule.filters', - 'signal.rule.rule_id': 'signal.rule.rule_id', - 'signal.rule.false_positives': 'signal.rule.false_positives', - 'signal.rule.max_signals': 'signal.rule.max_signals', - 'signal.rule.risk_score': 'signal.rule.risk_score', - 'signal.rule.description': 'signal.rule.description', - 'signal.rule.name': 'signal.rule.name', - 'signal.rule.immutable': 'signal.rule.immutable', - 'signal.rule.references': 'signal.rule.references', - 'signal.rule.severity': 'signal.rule.severity', - 'signal.rule.tags': 'signal.rule.tags', - 'signal.rule.threat': 'signal.rule.threat', - 'signal.rule.type': 'signal.rule.type', - 'signal.rule.size': 'signal.rule.size', - 'signal.rule.enabled': 'signal.rule.enabled', - 'signal.rule.created_at': 'signal.rule.created_at', - 'signal.rule.updated_at': 'signal.rule.updated_at', - 'signal.rule.created_by': 'signal.rule.created_by', - 'signal.rule.updated_by': 'signal.rule.updated_by', - 'signal.rule.version': 'signal.rule.version', - 'signal.rule.note': 'signal.rule.note', - 'signal.rule.threshold': 'signal.rule.threshold', - 'signal.rule.exceptions_list': 'signal.rule.exceptions_list', - 'signal.status': 'signal.status', -}; - -export const ruleFieldsMap: Readonly> = { - 'rule.reference': 'rule.reference', -}; - -export const eventFieldsMap: Readonly> = { - timestamp: '@timestamp', - '@timestamp': '@timestamp', - message: 'message', - ...{ ...agentFieldsMap }, - ...{ ...auditdMap }, - ...{ ...destinationFieldsMap }, - ...{ ...dnsFieldsMap }, - ...{ ...endgameFieldsMap }, - ...{ ...eventBaseFieldsMap }, - ...{ ...fileMap }, - ...{ ...geoFieldsMap }, - ...{ ...hostFieldsMap }, - ...{ ...networkFieldsMap }, - ...{ ...ruleFieldsMap }, - ...{ ...signalFieldsMap }, - ...{ ...sourceFieldsMap }, - ...{ ...suricataFieldsMap }, - ...{ ...systemFieldsMap }, - ...{ ...tlsFieldsMap }, - ...{ ...zeekFieldsMap }, - ...{ ...httpFieldsMap }, - ...{ ...userFieldsMap }, - ...{ ...winlogFieldsMap }, - ...{ ...processFieldsMap }, -}; diff --git a/x-pack/plugins/security_solution/server/lib/framework/kibana_framework_adapter.ts b/x-pack/plugins/security_solution/server/lib/framework/kibana_framework_adapter.ts deleted file mode 100644 index 56c1c802fdd68b..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/framework/kibana_framework_adapter.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 { KibanaRequest } from '../../../../../../src/core/server'; -import { IndexPatternsFetcher, UI_SETTINGS } from '../../../../../../src/plugins/data/server'; -import { AuthenticatedUser } from '../../../../security/common/model'; -import type { SecuritySolutionRequestHandlerContext } from '../../types'; - -import { - FrameworkAdapter, - FrameworkIndexPatternsService, - FrameworkRequest, - internalFrameworkRequest, -} from './types'; - -export class KibanaBackendFrameworkAdapter implements FrameworkAdapter { - public async callWithRequest( - req: FrameworkRequest, - endpoint: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - params: Record - ) { - const { elasticsearch, uiSettings } = req.context.core; - const includeFrozen = await uiSettings.client.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN); - const maxConcurrentShardRequests = - endpoint === 'msearch' - ? await uiSettings.client.get(UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS) - : 0; - - return elasticsearch.legacy.client.callAsCurrentUser(endpoint, { - ...params, - ignore_throttled: !includeFrozen, - ...(maxConcurrentShardRequests > 0 - ? { max_concurrent_shard_requests: maxConcurrentShardRequests } - : {}), - }); - } - - public getIndexPatternsService(request: FrameworkRequest): FrameworkIndexPatternsService { - return new IndexPatternsFetcher(request.context.core.elasticsearch.client.asCurrentUser, true); - } -} - -export function wrapRequest( - request: KibanaRequest, - context: SecuritySolutionRequestHandlerContext, - user: AuthenticatedUser | null -): FrameworkRequest { - return { - [internalFrameworkRequest]: request, - body: request.body, - context, - user, - }; -} diff --git a/x-pack/plugins/security_solution/server/lib/framework/types.ts b/x-pack/plugins/security_solution/server/lib/framework/types.ts index 6665468a271250..eceff4b35f74f1 100644 --- a/x-pack/plugins/security_solution/server/lib/framework/types.ts +++ b/x-pack/plugins/security_solution/server/lib/framework/types.ts @@ -5,124 +5,14 @@ * 2.0. */ -import { IndicesGetMappingParams } from 'elasticsearch'; - import { KibanaRequest } from '../../../../../../src/core/server'; import { AuthenticatedUser } from '../../../../security/common/model'; -import { ESQuery } from '../../../common/typed_json'; import type { SecuritySolutionRequestHandlerContext } from '../../types'; -import { - DocValueFieldsInput, - PaginationInput, - PaginationInputPaginated, - SortField, - TimerangeInput, -} from '../../../common/search_strategy'; -import { SourceConfiguration } from '../sources'; export const internalFrameworkRequest = Symbol('internalFrameworkRequest'); -export interface FrameworkAdapter { - callWithRequest( - req: FrameworkRequest, - method: 'search', - options?: object - ): Promise>; - callWithRequest( - req: FrameworkRequest, - method: 'msearch', - options?: object - ): Promise>; - callWithRequest( - req: FrameworkRequest, - method: 'indices.getMapping', - options?: IndicesGetMappingParams - ): Promise; - getIndexPatternsService(req: FrameworkRequest): FrameworkIndexPatternsService; -} - export interface FrameworkRequest extends Pick { [internalFrameworkRequest]: KibanaRequest; context: SecuritySolutionRequestHandlerContext; user: AuthenticatedUser | null; } - -export interface DatabaseResponse { - took: number; - timeout: boolean; -} - -export interface DatabaseSearchResponse - extends DatabaseResponse { - _shards: { - total: number; - successful: number; - skipped: number; - failed: number; - }; - aggregations?: Aggregations; - hits: { - total: number; - hits: Hit[]; - }; -} - -export interface DatabaseMultiResponse extends DatabaseResponse { - responses: Array>; -} - -export interface MappingProperties { - type: string; - path: string; - ignore_above: number; - properties: Readonly>>; -} - -export interface MappingResponse { - [indexName: string]: { - mappings: { - _meta: { - beat: string; - version: string; - }; - dynamic_templates: object[]; - date_detection: boolean; - properties: Readonly>>; - }; - }; -} - -interface FrameworkIndexFieldDescriptor { - aggregatable: boolean; - esTypes: string[]; - name: string; - readFromDocValues: boolean; - searchable: boolean; - type: string; -} - -export interface FrameworkIndexPatternsService { - getFieldsForWildcard(options: { - pattern: string | string[]; - }): Promise; -} - -export interface RequestBasicOptions { - sourceConfiguration: SourceConfiguration; - timerange: TimerangeInput; - filterQuery: ESQuery | undefined; - defaultIndex: string[]; - docValueFields?: DocValueFieldsInput[]; -} - -export interface RequestOptions extends RequestBasicOptions { - pagination: PaginationInput; - fields: readonly string[]; - sortField?: SortField; -} - -export interface RequestOptionsPaginated extends RequestBasicOptions { - pagination: PaginationInputPaginated; - fields: readonly string[]; - sortField?: SortField; -} diff --git a/x-pack/plugins/security_solution/server/lib/index_fields/elasticsearch_adapter.ts b/x-pack/plugins/security_solution/server/lib/index_fields/elasticsearch_adapter.ts deleted file mode 100644 index 81e65fc897d368..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/index_fields/elasticsearch_adapter.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 { FrameworkRequest } from '../framework'; -import { FieldsAdapter } from './types'; - -export class ElasticsearchIndexFieldAdapter implements FieldsAdapter { - // Deprecated until we delete all the code - public async getIndexFields(request: FrameworkRequest, indices: string[]): Promise { - return Promise.resolve(['deprecated']); - } -} diff --git a/x-pack/plugins/security_solution/server/lib/index_fields/index.ts b/x-pack/plugins/security_solution/server/lib/index_fields/index.ts deleted file mode 100644 index 11aba3bf679749..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/index_fields/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 { FieldsAdapter } from './types'; -import { FrameworkRequest } from '../framework'; -export { ElasticsearchIndexFieldAdapter } from './elasticsearch_adapter'; - -export class IndexFields { - constructor(private readonly adapter: FieldsAdapter) {} - - // Deprecated until we delete all the code - public async getFields(request: FrameworkRequest, defaultIndex: string[]): Promise { - return this.adapter.getIndexFields(request, defaultIndex); - } -} diff --git a/x-pack/plugins/security_solution/server/lib/index_fields/mock.ts b/x-pack/plugins/security_solution/server/lib/index_fields/mock.ts deleted file mode 100644 index c82f8cf7f916f4..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/index_fields/mock.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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 { IndexFieldDescriptor } from './types'; - -export const mockAuditbeatIndexField: IndexFieldDescriptor[] = [ - { - name: '@timestamp', - searchable: true, - type: 'date', - aggregatable: true, - }, - { - name: 'agent.ephemeral_id', - searchable: true, - type: 'string', - aggregatable: true, - }, - { - name: 'agent.name', - searchable: true, - type: 'string', - aggregatable: true, - }, - { - name: 'agent.type', - searchable: true, - type: 'string', - aggregatable: true, - }, - { - name: 'agent.version', - searchable: true, - type: 'string', - aggregatable: true, - }, -]; - -export const mockFilebeatIndexField: IndexFieldDescriptor[] = [ - { - name: '@timestamp', - searchable: true, - type: 'date', - aggregatable: true, - }, - { - name: 'agent.hostname', - searchable: true, - type: 'string', - aggregatable: true, - }, - { - name: 'agent.name', - searchable: true, - type: 'string', - aggregatable: true, - }, - { - name: 'agent.version', - searchable: true, - type: 'string', - aggregatable: true, - }, -]; - -export const mockPacketbeatIndexField: IndexFieldDescriptor[] = [ - { - name: '@timestamp', - searchable: true, - type: 'date', - aggregatable: true, - }, - { - name: 'agent.id', - searchable: true, - type: 'string', - aggregatable: true, - }, - { - name: 'agent.type', - searchable: true, - type: 'string', - aggregatable: true, - }, -]; diff --git a/x-pack/plugins/security_solution/server/lib/index_fields/types.ts b/x-pack/plugins/security_solution/server/lib/index_fields/types.ts deleted file mode 100644 index 8426742ed723a4..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/index_fields/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 { FrameworkRequest } from '../framework'; -import { IFieldSubType } from '../../../../../../src/plugins/data/common'; - -export interface FieldsAdapter { - getIndexFields(req: FrameworkRequest, indices: string[]): Promise; -} - -export interface IndexFieldDescriptor { - name: string; - type: string; - searchable: boolean; - aggregatable: boolean; - esTypes?: string[]; - subType?: IFieldSubType; -} diff --git a/x-pack/plugins/security_solution/server/lib/source_status/elasticsearch_adapter.ts b/x-pack/plugins/security_solution/server/lib/source_status/elasticsearch_adapter.ts deleted file mode 100644 index 3da0c1675e81eb..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/source_status/elasticsearch_adapter.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 { FrameworkAdapter, FrameworkRequest } from '../framework'; -import { SourceStatusAdapter } from './index'; -import { buildQuery } from './query.dsl'; -import { ApmServiceNameAgg } from './types'; -import { ENDPOINT_METADATA_INDEX } from '../../../common/constants'; - -const APM_INDEX_NAME = 'apm-*-transaction*'; -const APM_DATA_STREAM = 'traces-apm*'; - -export class ElasticsearchSourceStatusAdapter implements SourceStatusAdapter { - constructor(private readonly framework: FrameworkAdapter) {} - - public async hasIndices(request: FrameworkRequest, indexNames: string[]) { - // Intended flow to determine app-empty state is to first check siem indices (as this is a quick shard count), and - // if no shards exist only then perform the heavier APM query. This optimizes for normal use when siem data exists - try { - // Add endpoint metadata index to indices to check - indexNames.push(ENDPOINT_METADATA_INDEX); - // Remove APM index if exists, and only query if length > 0 in case it's the only index provided - const nonApmIndexNames = indexNames.filter( - (name) => name !== APM_INDEX_NAME && name !== APM_DATA_STREAM - ); - const indexCheckResponse = await (nonApmIndexNames.length > 0 - ? this.framework.callWithRequest(request, 'search', { - index: nonApmIndexNames, - size: 0, - terminate_after: 1, - allow_no_indices: true, - }) - : Promise.resolve(undefined)); - - if ((indexCheckResponse?._shards.total ?? -1) > 0) { - return true; - } - - // Note: Additional check necessary for APM-specific index. For details see: https://github.com/elastic/kibana/issues/56363 - // Only verify if APM data exists if indexNames includes `apm-*-transaction*` (default included apm index) - const includesApmIndex = - indexNames.includes(APM_INDEX_NAME) || indexNames.includes(APM_DATA_STREAM); - const hasApmDataResponse = await (includesApmIndex - ? this.framework.callWithRequest<{}, ApmServiceNameAgg>( - request, - 'search', - buildQuery({ defaultIndex: [APM_INDEX_NAME] }) - ) - : Promise.resolve(undefined)); - - if ((hasApmDataResponse?.aggregations?.total_service_names?.value ?? -1) > 0) { - return true; - } - } catch (e) { - if (e.status === 404) { - return false; - } - throw e; - } - - return false; - } -} diff --git a/x-pack/plugins/security_solution/server/lib/source_status/index.ts b/x-pack/plugins/security_solution/server/lib/source_status/index.ts deleted file mode 100644 index cecccb6e545a7d..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/source_status/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 { FrameworkRequest } from '../framework'; -export { ElasticsearchSourceStatusAdapter } from './elasticsearch_adapter'; - -export class SourceStatus { - constructor(private readonly adapter: SourceStatusAdapter) {} - - public async hasIndices(request: FrameworkRequest, indexes: string[]): Promise { - return this.adapter.hasIndices(request, indexes); - } -} - -export interface SourceStatusAdapter { - hasIndices(request: FrameworkRequest, indexNames: string[]): Promise; -} diff --git a/x-pack/plugins/security_solution/server/lib/source_status/query.dsl.ts b/x-pack/plugins/security_solution/server/lib/source_status/query.dsl.ts deleted file mode 100644 index 844404614e255b..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/source_status/query.dsl.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -const SERVICE_NAME = 'service.name'; - -export const buildQuery = ({ defaultIndex }: { defaultIndex: string[] }) => { - return { - allowNoIndices: true, - index: defaultIndex, - ignoreUnavailable: true, - terminate_after: 1, - body: { - size: 0, - aggs: { - total_service_names: { - cardinality: { - field: SERVICE_NAME, - }, - }, - }, - }, - track_total_hits: false, - }; -}; diff --git a/x-pack/plugins/security_solution/server/lib/source_status/types.ts b/x-pack/plugins/security_solution/server/lib/source_status/types.ts deleted file mode 100644 index 02fa60310b70aa..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/source_status/types.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface ApmServiceNameAgg { - total_service_names: { - value: number; - }; -} diff --git a/x-pack/plugins/security_solution/server/lib/sources/configuration.test.ts b/x-pack/plugins/security_solution/server/lib/sources/configuration.test.ts deleted file mode 100644 index 26bd43fbc4ff1f..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/sources/configuration.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DEFAULT_INDEX_PATTERN } from '../../../common/constants'; -import { InmemoryConfigurationAdapter } from '../configuration/inmemory_configuration_adapter'; -import { ConfigurationSourcesAdapter } from './configuration'; -import { PartialSourceConfiguration } from './types'; - -describe('the ConfigurationSourcesAdapter', () => { - test('adds the default source when no sources are configured', async () => { - const sourcesAdapter = new ConfigurationSourcesAdapter( - new InmemoryConfigurationAdapter({ sources: {} }) - ); - - expect(await sourcesAdapter.getAll()).toMatchObject({ - default: { - fields: { - container: expect.any(String), - host: expect.any(String), - message: expect.arrayContaining([expect.any(String)]), - pod: expect.any(String), - tiebreaker: expect.any(String), - timestamp: expect.any(String), - }, - }, - }); - }); - - test('adds missing aliases to default source when they are missing from the configuration', async () => { - const sourcesAdapter = new ConfigurationSourcesAdapter( - new InmemoryConfigurationAdapter({ - sources: { - default: {} as PartialSourceConfiguration, - }, - }) - ); - - expect(await sourcesAdapter.getAll()).toMatchObject({ - default: {}, - }); - }); - - test('adds missing fields to default source when they are missing from the configuration', async () => { - const sourcesAdapter = new ConfigurationSourcesAdapter( - new InmemoryConfigurationAdapter({ - sources: { - default: { - fields: { - container: 'DIFFERENT_CONTAINER_FIELD', - }, - } as PartialSourceConfiguration, - }, - }) - ); - - expect(await sourcesAdapter.getAll()).toMatchObject({ - default: { - fields: { - container: 'DIFFERENT_CONTAINER_FIELD', - host: expect.any(String), - message: expect.arrayContaining([expect.any(String)]), - pod: expect.any(String), - tiebreaker: expect.any(String), - timestamp: expect.any(String), - }, - }, - }); - }); - - test('adds missing fields to non-default sources when they are missing from the configuration', async () => { - const sourcesAdapter = new ConfigurationSourcesAdapter( - new InmemoryConfigurationAdapter({ - sources: { - sourceOne: { - defaultIndex: DEFAULT_INDEX_PATTERN, - fields: { - container: 'DIFFERENT_CONTAINER_FIELD', - }, - }, - }, - }) - ); - - expect(await sourcesAdapter.getAll()).toMatchObject({ - sourceOne: { - fields: { - container: 'DIFFERENT_CONTAINER_FIELD', - host: expect.any(String), - message: expect.arrayContaining([expect.any(String)]), - pod: expect.any(String), - tiebreaker: expect.any(String), - timestamp: expect.any(String), - }, - }, - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/sources/configuration.ts b/x-pack/plugins/security_solution/server/lib/sources/configuration.ts deleted file mode 100644 index d6f84e3c27b61b..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/sources/configuration.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 { ConfigurationAdapter } from '../configuration'; -import { InmemoryConfigurationAdapter } from '../configuration/inmemory_configuration_adapter'; - -import { SourcesAdapter, SourceConfiguration } from './index'; -import { PartialSourceConfigurations } from './types'; - -interface ConfigurationWithSources { - sources?: PartialSourceConfigurations; -} - -export class ConfigurationSourcesAdapter implements SourcesAdapter { - private readonly configuration: ConfigurationAdapter; - - constructor( - configuration: ConfigurationAdapter = new InmemoryConfigurationAdapter( - { sources: {} } - ) - ) { - this.configuration = configuration; - } - - public async getAll() { - const sourceConfigurations = (await this.configuration.get()).sources || { - default: DEFAULT_SOURCE, - }; - const sourceConfigurationsWithDefault = { - ...sourceConfigurations, - default: { - ...DEFAULT_SOURCE, - ...(sourceConfigurations.default || {}), - }, - } as PartialSourceConfigurations; - - return Object.entries(sourceConfigurationsWithDefault).reduce< - Record - >( - (result, [sourceId, sourceConfiguration]) => ({ - ...result, - [sourceId]: { - ...sourceConfiguration, - fields: { - ...DEFAULT_FIELDS, - ...(sourceConfiguration.fields || {}), - }, - }, - }), - {} - ); - } -} - -const DEFAULT_FIELDS = { - container: 'docker.container.name', - host: 'beat.hostname', - message: ['message', '@message'], - pod: 'kubernetes.pod.name', - tiebreaker: '_doc', - timestamp: '@timestamp', -}; - -const DEFAULT_SOURCE = { - fields: DEFAULT_FIELDS, -}; diff --git a/x-pack/plugins/security_solution/server/lib/sources/index.ts b/x-pack/plugins/security_solution/server/lib/sources/index.ts deleted file mode 100644 index 3baf35619ac195..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/sources/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 { ConfigurationSourcesAdapter } from './configuration'; - -export class Sources { - constructor(private readonly adapter: SourcesAdapter) {} - - public async getConfiguration(sourceId: string): Promise { - const sourceConfigurations = await this.getAllConfigurations(); - const requestedSourceConfiguration = sourceConfigurations[sourceId]; - if (!requestedSourceConfiguration) { - throw new Error(`Failed to find source '${sourceId}'`); - } - - return requestedSourceConfiguration; - } - - public getAllConfigurations() { - return this.adapter.getAll(); - } -} - -export interface SourcesAdapter { - getAll(): Promise>; -} - -export interface AliasConfiguration { - defaultIndex: string[]; -} - -export interface SourceConfiguration extends AliasConfiguration { - fields: { - container: string; - host: string; - message: string[]; - pod: string; - tiebreaker: string; - timestamp: string; - }; -} diff --git a/x-pack/plugins/security_solution/server/lib/sources/types.ts b/x-pack/plugins/security_solution/server/lib/sources/types.ts deleted file mode 100644 index 424505d789d21d..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/sources/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 { SourceConfiguration } from './index'; - -export type PartialSourceConfigurations = { - default?: PartialDefaultSourceConfiguration; -} & { - [sourceId: string]: PartialSourceConfiguration; -}; - -export type PartialDefaultSourceConfiguration = { - fields?: Partial; -} & Partial>>; - -export type PartialSourceConfiguration = { - fields?: Partial; -} & Pick>; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/diagnostic_task.ts b/x-pack/plugins/security_solution/server/lib/telemetry/diagnostic_task.ts index c83f37593a0363..f8c3ca914abe1d 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/diagnostic_task.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/diagnostic_task.ts @@ -108,7 +108,9 @@ export class TelemetryDiagTask { } this.logger.debug(`Received ${hits.length} diagnostic alerts`); - const diagAlerts: TelemetryEvent[] = hits.map((h) => h._source); + const diagAlerts: TelemetryEvent[] = hits.flatMap((h) => + h._source != null ? [h._source] : [] + ); this.sender.queueTelemetryEvents(diagAlerts); return diagAlerts.length; }; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 6f9279d04b3480..bdd301d9fea1d7 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -7,8 +7,8 @@ import { cloneDeep } from 'lodash'; import axios from 'axios'; +import { SavedObjectsClientContract } from 'kibana/server'; import { SearchRequest } from '@elastic/elasticsearch/api/types'; -import { LegacyAPICaller, SavedObjectsClientContract } from 'kibana/server'; import { URL } from 'url'; import { CoreStart, ElasticsearchClient, Logger } from 'src/core/server'; import { TelemetryPluginStart, TelemetryPluginSetup } from 'src/plugins/telemetry/server'; @@ -48,7 +48,6 @@ export class TelemetryEventsSender { private readonly checkIntervalMs = 60 * 1000; private readonly max_records = 10_000; private readonly logger: Logger; - private core?: CoreStart; private maxQueueSize = 100; private telemetryStart?: TelemetryPluginStart; private telemetrySetup?: TelemetryPluginSetup; @@ -83,7 +82,6 @@ export class TelemetryEventsSender { endpointContextService?: EndpointAppContextService ) { this.telemetryStart = telemetryStart; - this.core = core; this.esClient = core?.elasticsearch.client.asInternalUser; this.agentService = endpointContextService?.getAgentService(); this.agentPolicyService = endpointContextService?.getAgentPolicyService(); @@ -126,18 +124,18 @@ export class TelemetryEventsSender { sort: [ { 'event.ingested': { - order: 'desc', + order: 'desc' as const, }, }, ], }, }; - if (!this.core) { - throw Error('could not fetch diagnostic alerts. core is not available'); + if (this.esClient === undefined) { + throw Error('could not fetch diagnostic alerts. es client is not available'); } - const callCluster = this.core.elasticsearch.legacy.client.callAsInternalUser; - return callCluster('search', query); + + return (await this.esClient.search(query)).body; } public async fetchEndpointMetrics(executeFrom: string, executeTo: string) { @@ -374,11 +372,10 @@ export class TelemetryEventsSender { } private async fetchClusterInfo(): Promise { - if (!this.core) { - throw Error("Couldn't fetch cluster info because core is not available"); + if (this.esClient === undefined) { + throw Error("Couldn't fetch cluster info. es client is not available"); } - const callCluster = this.core.elasticsearch.legacy.client.callAsInternalUser; - return getClusterInfo(callCluster); + return getClusterInfo(this.esClient); } private async fetchTelemetryUrl(channel: string): Promise { @@ -390,12 +387,11 @@ export class TelemetryEventsSender { } private async fetchLicenseInfo(): Promise { - if (!this.core) { + if (!this.esClient) { return undefined; } try { - const callCluster = this.core.elasticsearch.legacy.client.callAsInternalUser; - const ret = await getLicense(callCluster, true); + const ret = await getLicense(this.esClient, true); return ret.license; } catch (err) { this.logger.warn(`Error retrieving license: ${err}`); @@ -615,13 +611,15 @@ export interface ESClusterInfo { /** * Get the cluster info from the connected cluster. - * + * Copied from: + * src/plugins/telemetry/server/telemetry_collection/get_cluster_info.ts * This is the equivalent to GET / * - * @param {function} callCluster The callWithInternalUser handler (exposed for testing) + * @param {function} esClient The asInternalUser handler (exposed for testing) */ -function getClusterInfo(callCluster: LegacyAPICaller) { - return callCluster('info'); +export async function getClusterInfo(esClient: ElasticsearchClient) { + const { body } = await esClient.info(); + return body; } // From https://www.elastic.co/guide/en/elasticsearch/reference/current/get-license.html @@ -639,14 +637,19 @@ export interface ESLicense { start_date_in_millis?: number; } -function getLicense(callCluster: LegacyAPICaller, local: boolean) { - return callCluster<{ license: ESLicense }>('transport.request', { - method: 'GET', - path: '/_license', - query: { - local, - // For versions >= 7.6 and < 8.0, this flag is needed otherwise 'platinum' is returned for 'enterprise' license. - accept_enterprise: 'true', - }, - }); +async function getLicense( + esClient: ElasticsearchClient, + local: boolean +): Promise<{ license: ESLicense }> { + return ( + await esClient.transport.request({ + method: 'GET', + path: '/_license', + querystring: { + local, + // For versions >= 7.6 and < 8.0, this flag is needed otherwise 'platinum' is returned for 'enterprise' license. + accept_enterprise: 'true', + }, + }) + ).body as Promise<{ license: ESLicense }>; // Note: We have to as cast since transport.request doesn't have generics } diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.test.ts index 2b3eda31916a80..bee39be6cbd5c2 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.test.ts @@ -18,7 +18,6 @@ import { } from '../../../../detection_engine/routes/__mocks__'; import { addPrepackagedRulesRequest, - getNonEmptyIndex, getFindResultWithSingleHit, } from '../../../../detection_engine/routes/__mocks__/request_responses'; @@ -47,7 +46,6 @@ describe('installPrepackagedTimelines', () => { authz: {}, } as unknown) as SecurityPluginSetup; - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getNonEmptyIndex()); clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); jest.doMock('./helpers', () => { diff --git a/x-pack/plugins/security_solution/server/lib/types.ts b/x-pack/plugins/security_solution/server/lib/types.ts index 6ef51bc3c53d48..31211869d054d0 100644 --- a/x-pack/plugins/security_solution/server/lib/types.ts +++ b/x-pack/plugins/security_solution/server/lib/types.ts @@ -5,38 +5,8 @@ * 2.0. */ -import { AuthenticatedUser } from '../../../security/common/model'; export { ConfigType as Configuration } from '../config'; -import type { SecuritySolutionRequestHandlerContext } from '../types'; - -import { FrameworkAdapter, FrameworkRequest } from './framework'; -import { IndexFields } from './index_fields'; -import { SourceStatus } from './source_status'; -import { Sources } from './sources'; -import { Notes } from './timeline/saved_object/notes'; -import { PinnedEvent } from './timeline/saved_object/pinned_events'; -import { Timeline } from './timeline/saved_object/timelines'; import { TotalValue, BaseHit, Explanation } from '../../common/detection_engine/types'; -import { SignalHit } from './detection_engine/signals/types'; - -export interface AppDomainLibs { - fields: IndexFields; -} - -export interface AppBackendLibs extends AppDomainLibs { - framework: FrameworkAdapter; - sources: Sources; - sourceStatus: SourceStatus; - timeline: Timeline; - note: Notes; - pinnedEvent: PinnedEvent; -} - -export interface SiemContext { - req: FrameworkRequest; - context: SecuritySolutionRequestHandlerContext; - user: AuthenticatedUser | null; -} export interface ShardsResponse { total: number; @@ -101,8 +71,6 @@ export interface SearchResponse extends BaseSearchResponse { export type SearchHit = SearchResponse['hits']['hits'][0]; -export type SearchSignalHit = SearchResponse['hits']['hits'][0]; - export interface TermAggregationBucket { key: string; doc_count: number; @@ -115,35 +83,3 @@ export interface TermAggregationBucket { value: number; }; } - -export interface TermAggregation { - [agg: string]: { - buckets: TermAggregationBucket[]; - }; -} - -export interface TotalHit { - value: number; - relation: string; -} - -export interface Hit { - _index: string; - _type: string; - _id: string; - _score: number | null; -} - -export interface Hits { - hits: { - total: T; - max_score: number | null; - hits: U[]; - }; -} - -export interface MSearchHeader { - index: string[] | string; - allowNoIndices?: boolean; - ignoreUnavailable?: boolean; -} diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 07b0e2ed4b9dd8..9d2e918d4f2745 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -46,7 +46,6 @@ import { SpacesPluginSetup as SpacesSetup } from '../../spaces/server'; import { ILicense, LicensingPluginStart } from '../../licensing/server'; import { FleetStartContract } from '../../fleet/server'; import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; -import { compose } from './lib/compose/kibana'; import { createQueryAlertType } from './lib/detection_engine/reference_rules/query'; import { createEqlAlertType } from './lib/detection_engine/reference_rules/eql'; import { createThresholdAlertType } from './lib/detection_engine/reference_rules/threshold'; @@ -317,8 +316,6 @@ export class Plugin implements IPlugin { const securitySolutionSearchStrategy = securitySolutionSearchStrategyProvider( depsStart.data, diff --git a/x-pack/plugins/security_solution/server/utils/build_query/calculate_timeseries_interval.ts b/x-pack/plugins/security_solution/server/utils/build_query/calculate_timeseries_interval.ts index c3be85a5e3a3c4..071d1d6b4db2fb 100644 --- a/x-pack/plugins/security_solution/server/utils/build_query/calculate_timeseries_interval.ts +++ b/x-pack/plugins/security_solution/server/utils/build_query/calculate_timeseries_interval.ts @@ -10,86 +10,6 @@ ** x-pack/plugins/apm/server/lib/helpers/get_bucket_size/calculate_auto.js */ import moment from 'moment'; -import { get } from 'lodash/fp'; -const d = moment.duration; - -const roundingRules = [ - [d(500, 'ms'), d(100, 'ms')], - [d(5, 'second'), d(1, 'second')], - [d(7.5, 'second'), d(5, 'second')], - [d(15, 'second'), d(10, 'second')], - [d(45, 'second'), d(30, 'second')], - [d(3, 'minute'), d(1, 'minute')], - [d(9, 'minute'), d(5, 'minute')], - [d(20, 'minute'), d(10, 'minute')], - [d(45, 'minute'), d(30, 'minute')], - [d(2, 'hour'), d(1, 'hour')], - [d(6, 'hour'), d(3, 'hour')], - [d(24, 'hour'), d(12, 'hour')], - [d(1, 'week'), d(1, 'd')], - [d(3, 'week'), d(1, 'week')], - [d(1, 'year'), d(1, 'month')], - [Infinity, d(1, 'year')], -]; - -const revRoundingRules = roundingRules.slice(0).reverse(); - -const find = ( - rules: Array>, - check: ( - bound: number | moment.Duration, - interval: number | moment.Duration, - target: number - ) => number | moment.Duration | undefined, - last?: boolean -): ((buckets: number, duration: number | moment.Duration) => moment.Duration | undefined) => { - const pick = (buckets: number, duration: number | moment.Duration): number | moment.Duration => { - const target = - typeof duration === 'number' ? duration / buckets : duration.asMilliseconds() / buckets; - let lastResp = null; - - for (let i = 0; i < rules.length; i++) { - const rule = rules[i]; - const resp = check(rule[0], rule[1], target); - - if (resp == null) { - if (last) { - if (lastResp) return lastResp; - break; - } - } - - if (!last && resp) return resp; - lastResp = resp; - } - - // fallback to just a number of milliseconds, ensure ms is >= 1 - const ms = Math.max(Math.floor(target), 1); - return moment.duration(ms, 'ms'); - }; - - return (buckets, duration) => { - const interval = pick(buckets, duration); - const intervalData = get('_data', interval); - if (intervalData) return moment.duration(intervalData); - }; -}; - -export const calculateAuto = { - near: find( - revRoundingRules, - (bound, interval, target) => { - if (bound > target) return interval; - }, - true - ), - lessThan: find(revRoundingRules, (_bound, interval, target) => { - if (interval < target) return interval; - }), - atLeast: find(revRoundingRules, (_bound, interval, target) => { - if (interval <= target) return interval; - }), -}; export const calculateTimeSeriesInterval = (from: string, to: string) => { return `${Math.floor(moment(to).diff(moment(from)) / 32)}ms`; diff --git a/x-pack/plugins/security_solution/server/utils/read_stream/create_stream_from_ndjson.ts b/x-pack/plugins/security_solution/server/utils/read_stream/create_stream_from_ndjson.ts index b0b70aeb3ea340..42f1b467ed4c2d 100644 --- a/x-pack/plugins/security_solution/server/utils/read_stream/create_stream_from_ndjson.ts +++ b/x-pack/plugins/security_solution/server/utils/read_stream/create_stream_from_ndjson.ts @@ -7,19 +7,9 @@ import { Transform } from 'stream'; import { has, isString } from 'lodash/fp'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import * as t from 'io-ts'; import { createMapStream, createFilterStream } from '@kbn/utils'; -import { exactCheck, formatErrors } from '@kbn/securitysolution-io-ts-utils'; -import { BadRequestError } from '@kbn/securitysolution-es-utils'; -import { importRuleValidateTypeDependents } from '../../../common/detection_engine/schemas/request/import_rules_type_dependents'; -import { - ImportRulesSchemaDecoded, - importRulesSchema, - ImportRulesSchema, -} from '../../../common/detection_engine/schemas/request/import_rules_schema'; +import { ImportRulesSchemaDecoded } from '../../../common/detection_engine/schemas/request/import_rules_schema'; export interface RulesObjectsExportResultDetails { /** number of successfully exported objects */ @@ -44,29 +34,6 @@ export const filterExportedCounts = (): Transform => { ); }; -export const validateRules = (): Transform => { - return createMapStream((obj: ImportRulesSchema) => { - if (!(obj instanceof Error)) { - const decoded = importRulesSchema.decode(obj); - const checked = exactCheck(obj, decoded); - const onLeft = (errors: t.Errors): BadRequestError | ImportRulesSchemaDecoded => { - return new BadRequestError(formatErrors(errors).join()); - }; - const onRight = (schema: ImportRulesSchema): BadRequestError | ImportRulesSchemaDecoded => { - const validationErrors = importRuleValidateTypeDependents(schema); - if (validationErrors.length) { - return new BadRequestError(validationErrors.join()); - } else { - return schema as ImportRulesSchemaDecoded; - } - }; - return pipe(checked, fold(onLeft, onRight)); - } else { - return obj; - } - }); -}; - // Adaptation from: saved_objects/import/create_limit_stream.ts export const createLimitStream = (limit: number): Transform => { let counter = 0; diff --git a/x-pack/plugins/security_solution/server/utils/runtime_types.ts b/x-pack/plugins/security_solution/server/utils/runtime_types.ts index 5d1971a4223e38..50045568357a07 100644 --- a/x-pack/plugins/security_solution/server/utils/runtime_types.ts +++ b/x-pack/plugins/security_solution/server/utils/runtime_types.ts @@ -5,15 +5,10 @@ * 2.0. */ -import { either, fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; +import { either } from 'fp-ts/lib/Either'; import * as rt from 'io-ts'; -import { failure } from 'io-ts/lib/PathReporter'; import get from 'lodash/get'; -type ErrorFactory = (message: string) => Error; - export type GenericIntersectionC = // eslint-disable-next-line @typescript-eslint/no-explicit-any | rt.IntersectionC<[any, any]> @@ -24,18 +19,6 @@ export type GenericIntersectionC = // eslint-disable-next-line @typescript-eslint/no-explicit-any | rt.IntersectionC<[any, any, any, any, any]>; -export const createPlainError = (message: string) => new Error(message); - -export const throwErrors = (createError: ErrorFactory) => (errors: rt.Errors) => { - throw createError(failure(errors).join('\n')); -}; - -export const decodeOrThrow = ( - runtimeType: rt.Type, - createError: ErrorFactory = createPlainError -) => (inputValue: I) => - pipe(runtimeType.decode(inputValue), fold(throwErrors(createError), identity)); - const getProps = ( codec: | rt.HasProps