From dc5f448076fe542e9e54fe48a530f034d507f758 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Mon, 15 Jun 2020 15:22:24 -0400 Subject: [PATCH 1/3] [Endpoint] Remove dependency on ingest for the index patterns (#69058) * Remove dependency on ingest for the index patterns * Fixing the tests * Fixing test * Use variable instead of class --- .../common/endpoint/constants.ts | 10 +++ .../common/endpoint_alerts/alert_constants.ts | 8 -- .../endpoint_alerts/store/middleware.ts | 9 +- .../endpoint/alerts/handlers/alerts.test.ts | 3 +- .../endpoint/alerts/handlers/details/index.ts | 7 +- .../endpoint/alerts/handlers/index_pattern.ts | 28 ------- .../endpoint/alerts/handlers/list/index.ts | 6 +- .../server/endpoint/alerts/index_pattern.ts | 83 ------------------- .../server/endpoint/alerts/routes.ts | 13 --- .../endpoint_app_context_services.test.ts | 1 - .../endpoint/endpoint_app_context_services.ts | 15 +--- .../server/endpoint/mocks.ts | 26 ------ .../server/endpoint/routes/metadata/index.ts | 11 +-- .../endpoint/routes/metadata/metadata.test.ts | 7 +- .../routes/metadata/query_builders.test.ts | 14 ++-- .../endpoint/routes/policy/handlers.test.ts | 7 +- .../server/endpoint/routes/policy/handlers.ts | 7 +- .../endpoint/routes/resolver/ancestry.ts | 6 +- .../endpoint/routes/resolver/children.ts | 6 +- .../server/endpoint/routes/resolver/events.ts | 5 +- .../server/endpoint/routes/resolver/tree.ts | 5 +- .../security_solution/server/plugin.ts | 5 -- .../apis/endpoint/alerts/index.ts | 3 +- .../apis/endpoint/alerts/index_pattern.ts | 32 ------- .../apis/endpoint/data_stream_helper.ts | 11 ++- .../api_integration/apis/endpoint/index.ts | 2 - .../apis/alerts/index.ts | 2 +- .../apis/alerts/index_pattern.ts | 16 ---- .../apis/index.ts | 1 - .../apis/metadata.ts | 2 +- 30 files changed, 53 insertions(+), 298 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/endpoint/constants.ts delete mode 100644 x-pack/plugins/security_solution/server/endpoint/alerts/handlers/index_pattern.ts delete mode 100644 x-pack/plugins/security_solution/server/endpoint/alerts/index_pattern.ts delete mode 100644 x-pack/test/api_integration/apis/endpoint/alerts/index_pattern.ts delete mode 100644 x-pack/test/endpoint_api_integration_no_ingest/apis/alerts/index_pattern.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts new file mode 100644 index 00000000000000..bb00321567e80b --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const eventsIndexPattern = 'events-endpoint-*'; +export const metadataIndexPattern = 'metrics-endpoint.metadata-*'; +export const policyIndexPattern = 'metrics-endpoint.policy-*'; +export const telemetryIndexPattern = 'metrics-endpoint.telemetry-*'; diff --git a/x-pack/plugins/security_solution/common/endpoint_alerts/alert_constants.ts b/x-pack/plugins/security_solution/common/endpoint_alerts/alert_constants.ts index 66de2b85ef3a78..cb0e5f67c701b4 100644 --- a/x-pack/plugins/security_solution/common/endpoint_alerts/alert_constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint_alerts/alert_constants.ts @@ -9,14 +9,6 @@ export class AlertConstants { * The prefix for all Alert APIs */ static BASE_API_URL = '/api/endpoint'; - /** - * The path for the Alert's Index Pattern API. - */ - static INDEX_PATTERN_ROUTE = `${AlertConstants.BASE_API_URL}/index_pattern`; - /** - * A paramter passed to Alert's Index Pattern. - */ - static EVENT_DATASET = 'events'; /** * Alert's Search API default page size */ diff --git a/x-pack/plugins/security_solution/public/endpoint_alerts/store/middleware.ts b/x-pack/plugins/security_solution/public/endpoint_alerts/store/middleware.ts index dd84b4fcff5bdd..cd7ed93d22d9f3 100644 --- a/x-pack/plugins/security_solution/public/endpoint_alerts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/endpoint_alerts/store/middleware.ts @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import { eventsIndexPattern } from '../../../common/endpoint/constants'; import { IIndexPattern } from '../../../../../../src/plugins/data/public'; import { AlertResultList, AlertDetails, AlertListState, } from '../../../common/endpoint_alerts/types'; -import { AlertConstants } from '../../../common/endpoint_alerts/alert_constants'; import { ImmutableMiddlewareFactory } from '../../common/store'; import { cloneHttpFetchQuery } from '../../common/utils/clone_http_fetch_query'; import { @@ -27,14 +27,11 @@ export const alertMiddlewareFactory: ImmutableMiddlewareFactory ) => { async function fetchIndexPatterns(): Promise { const { indexPatterns } = depsStart.data; - const eventsPattern: { indexPattern: string } = await coreStart.http.get( - `${AlertConstants.INDEX_PATTERN_ROUTE}/${AlertConstants.EVENT_DATASET}` - ); const fields = await indexPatterns.getFieldsForWildcard({ - pattern: eventsPattern.indexPattern, + pattern: eventsIndexPattern, }); const indexPattern: IIndexPattern = { - title: eventsPattern.indexPattern, + title: eventsIndexPattern, fields, }; diff --git a/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/alerts.test.ts b/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/alerts.test.ts index 37bf4bbfcbbb2c..fd785bca4aa246 100644 --- a/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/alerts.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/alerts.test.ts @@ -11,7 +11,7 @@ import { } from '../../../../../../../src/core/server/mocks'; import { registerAlertRoutes } from '../routes'; import { alertingIndexGetQuerySchema } from '../../../../common/endpoint_alerts/schema/alert_index'; -import { createMockAgentService, createMockIndexPatternRetriever } from '../../mocks'; +import { createMockAgentService } from '../../mocks'; import { EndpointAppContextService } from '../../endpoint_app_context_services'; import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__'; @@ -29,7 +29,6 @@ describe('test alerts route', () => { endpointAppContextService = new EndpointAppContextService(); endpointAppContextService.start({ - indexPatternRetriever: createMockIndexPatternRetriever('events-endpoint-*'), agentService: createMockAgentService(), }); diff --git a/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/details/index.ts b/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/details/index.ts index a4b07df6b8f8b8..5bb3f969807df3 100644 --- a/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/details/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/details/index.ts @@ -5,6 +5,7 @@ */ import { GetResponse } from 'elasticsearch'; import { KibanaRequest, RequestHandler } from 'kibana/server'; +import { eventsIndexPattern } from '../../../../../common/endpoint/constants'; import { AlertEvent } from '../../../../../common/endpoint/types'; import { EndpointAppContext } from '../../../types'; import { AlertDetailsRequestParams } from '../../../../../common/endpoint_alerts/types'; @@ -27,17 +28,13 @@ export const alertDetailsHandlerWrapper = function ( id: alertId.id, })) as GetResponse; - const indexPattern = await endpointAppContext.service - .getIndexPatternRetriever() - .getEventIndexPattern(ctx); - const config = await endpointAppContext.config(); const pagination: AlertDetailsPagination = new AlertDetailsPagination( config, ctx, req.params, response, - indexPattern + eventsIndexPattern ); const currentHostInfo = await getHostData( diff --git a/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/index_pattern.ts b/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/index_pattern.ts deleted file mode 100644 index cb40be586560fd..00000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/index_pattern.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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Logger, RequestHandler } from 'kibana/server'; -import { EndpointAppContext } from '../../types'; -import { IndexPatternGetParamsResult } from '../../../../common/endpoint_alerts/types'; - -export function handleIndexPattern( - log: Logger, - endpointAppContext: EndpointAppContext -): RequestHandler { - return async (context, req, res) => { - try { - const indexRetriever = endpointAppContext.service.getIndexPatternRetriever(); - return res.ok({ - body: { - indexPattern: await indexRetriever.getIndexPattern(context, req.params.datasetPath), - }, - }); - } catch (error) { - log.warn(error); - return res.notFound({ body: error }); - } - }; -} diff --git a/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/list/index.ts b/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/list/index.ts index 6eda863408b288..5122dd89bba165 100644 --- a/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/list/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/alerts/handlers/list/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { RequestHandler } from 'kibana/server'; +import { eventsIndexPattern } from '../../../../../common/endpoint/constants'; import { EndpointAppContext } from '../../../types'; import { searchESForAlerts } from '../lib'; import { getRequestData, mapToAlertResultList } from './lib'; @@ -18,14 +19,11 @@ export const alertListHandlerWrapper = function ( res ) => { try { - const indexPattern = await endpointAppContext.service - .getIndexPatternRetriever() - .getEventIndexPattern(ctx); const reqData = await getRequestData(req, endpointAppContext); const response = await searchESForAlerts( ctx.core.elasticsearch.legacy.client, reqData, - indexPattern + eventsIndexPattern ); const mappedBody = await mapToAlertResultList(ctx, endpointAppContext, reqData, response); return res.ok({ body: mappedBody }); diff --git a/x-pack/plugins/security_solution/server/endpoint/alerts/index_pattern.ts b/x-pack/plugins/security_solution/server/endpoint/alerts/index_pattern.ts deleted file mode 100644 index 391aedecdd0995..00000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/alerts/index_pattern.ts +++ /dev/null @@ -1,83 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { Logger, LoggerFactory, RequestHandlerContext } from 'kibana/server'; -import { AlertConstants } from '../../../common/endpoint_alerts/alert_constants'; -import { ESIndexPatternService } from '../../../../ingest_manager/server'; - -export interface IndexPatternRetriever { - getIndexPattern(ctx: RequestHandlerContext, datasetPath: string): Promise; - getEventIndexPattern(ctx: RequestHandlerContext): Promise; - getMetadataIndexPattern(ctx: RequestHandlerContext): Promise; - getPolicyResponseIndexPattern(ctx: RequestHandlerContext): Promise; -} - -/** - * This class is used to retrieve an index pattern. It should be used in the server side code whenever - * an index pattern is needed to query data within ES. The index pattern is constructed by the Ingest Manager - * based on the contents of the Endpoint Package in the Package Registry. - */ -export class IngestIndexPatternRetriever implements IndexPatternRetriever { - private static endpointPackageName = 'endpoint'; - private static metadataDataset = 'metadata'; - private static policyDataset = 'policy'; - private readonly log: Logger; - constructor(private readonly service: ESIndexPatternService, loggerFactory: LoggerFactory) { - this.log = loggerFactory.get('index-pattern-retriever'); - } - - /** - * Retrieves the index pattern for querying events within elasticsearch. - * - * @param ctx a RequestHandlerContext from a route handler - * @returns a string representing the index pattern (e.g. `events-endpoint-*`) - */ - async getEventIndexPattern(ctx: RequestHandlerContext) { - return this.getIndexPattern(ctx, AlertConstants.EVENT_DATASET); - } - - /** - * Retrieves the index pattern for querying endpoint metadata within elasticsearch. - * - * @param ctx a RequestHandlerContext from a route handler - * @returns a string representing the index pattern (e.g. `metrics-endpoint-*`) - */ - async getMetadataIndexPattern(ctx: RequestHandlerContext) { - return this.getIndexPattern(ctx, IngestIndexPatternRetriever.metadataDataset); - } - - /** - * Retrieves the index pattern for a specific dataset for querying endpoint data. - * - * @param ctx a RequestHandlerContext from a route handler - * @param datasetPath a string of the path being used for a dataset within the Endpoint Package - * (e.g. `events`, `metadata`) - * @returns a string representing the index pattern (e.g. `metrics-endpoint-*`) - */ - async getIndexPattern(ctx: RequestHandlerContext, datasetPath: string) { - try { - const pattern = await this.service.getESIndexPattern( - ctx.core.savedObjects.client, - IngestIndexPatternRetriever.endpointPackageName, - datasetPath - ); - - if (!pattern) { - const msg = `Unable to retrieve the index pattern for dataset: ${datasetPath}`; - this.log.warn(msg); - throw new Error(msg); - } - return pattern; - } catch (error) { - const errMsg = `Error occurred while retrieving pattern for: ${datasetPath} error: ${error}`; - this.log.warn(errMsg); - throw new Error(errMsg); - } - } - - async getPolicyResponseIndexPattern(ctx: RequestHandlerContext): Promise { - return this.getIndexPattern(ctx, IngestIndexPatternRetriever.policyDataset); - } -} diff --git a/x-pack/plugins/security_solution/server/endpoint/alerts/routes.ts b/x-pack/plugins/security_solution/server/endpoint/alerts/routes.ts index 07cca9e80d88b1..a0d0b562bdd0db 100644 --- a/x-pack/plugins/security_solution/server/endpoint/alerts/routes.ts +++ b/x-pack/plugins/security_solution/server/endpoint/alerts/routes.ts @@ -10,8 +10,6 @@ import { alertListHandlerWrapper } from './handlers/list'; import { alertDetailsHandlerWrapper } from './handlers/details'; import { alertDetailsReqSchema } from './handlers/details/schemas'; import { alertingIndexGetQuerySchema } from '../../../common/endpoint_alerts/schema/alert_index'; -import { indexPatternGetParamsSchema } from '../../../common/endpoint_alerts/schema/index_pattern'; -import { handleIndexPattern } from './handlers/index_pattern'; export const BASE_ALERTS_ROUTE = `${AlertConstants.BASE_API_URL}/alerts`; @@ -37,15 +35,4 @@ export function registerAlertRoutes(router: IRouter, endpointAppContext: Endpoin }, alertDetailsHandlerWrapper(endpointAppContext) ); - - const log = endpointAppContext.logFactory.get('index_pattern'); - - router.get( - { - path: `${AlertConstants.INDEX_PATTERN_ROUTE}/{datasetPath}`, - validate: { params: indexPatternGetParamsSchema }, - options: { authRequired: true }, - }, - handleIndexPattern(log, endpointAppContext) - ); } diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.test.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.test.ts index 943a9c22c6aaee..8cf2ada9907d33 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.test.ts @@ -8,7 +8,6 @@ import { EndpointAppContextService } from './endpoint_app_context_services'; describe('test endpoint app context services', () => { it('should throw error if start is not called', async () => { const endpointAppContextService = new EndpointAppContextService(); - expect(() => endpointAppContextService.getIndexPatternRetriever()).toThrow(Error); expect(() => endpointAppContextService.getAgentService()).toThrow(Error); }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index 5d74c75ebca5c4..cb8c913a73b8e8 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -3,7 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { IndexPatternRetriever } from './alerts/index_pattern'; import { AgentService } from '../../../ingest_manager/server'; /** @@ -11,14 +10,9 @@ import { AgentService } from '../../../ingest_manager/server'; * of the plugin lifecycle. And stop during the stop phase, if needed. */ export class EndpointAppContextService { - private indexPatternRetriever: IndexPatternRetriever | undefined; private agentService: AgentService | undefined; - public start(dependencies: { - indexPatternRetriever: IndexPatternRetriever; - agentService: AgentService; - }) { - this.indexPatternRetriever = dependencies.indexPatternRetriever; + public start(dependencies: { agentService: AgentService }) { this.agentService = dependencies.agentService; } @@ -30,11 +24,4 @@ export class EndpointAppContextService { } return this.agentService; } - - public getIndexPatternRetriever(): IndexPatternRetriever { - if (!this.indexPatternRetriever) { - throw new Error(`must call start on ${EndpointAppContextService.name} to call getter`); - } - return this.indexPatternRetriever; - } } diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index d1873cb18ce0a9..b10e9e4dc90e77 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -7,32 +7,6 @@ import { IScopedClusterClient, SavedObjectsClientContract } from 'kibana/server'; import { xpackMocks } from '../../../../mocks'; import { AgentService, IngestManagerStartContract } from '../../../ingest_manager/server'; -import { IndexPatternRetriever } from './alerts/index_pattern'; - -/** - * Creates a mock IndexPatternRetriever for use in tests. - * - * @param indexPattern a string index pattern to return when any of the mock's public methods are called. - * @returns the same string passed in via `indexPattern` - */ -export const createMockIndexPatternRetriever = (indexPattern: string): IndexPatternRetriever => { - const mockGetFunc = jest.fn().mockResolvedValue(indexPattern); - return { - getIndexPattern: mockGetFunc, - getEventIndexPattern: mockGetFunc, - getMetadataIndexPattern: mockGetFunc, - getPolicyResponseIndexPattern: mockGetFunc, - }; -}; - -export const MetadataIndexPattern = 'metrics-endpoint-*'; - -/** - * Creates a mock IndexPatternRetriever for use in tests that returns `metrics-endpoint-*` - */ -export const createMockMetadataIndexPatternRetriever = () => { - return createMockIndexPatternRetriever(MetadataIndexPattern); -}; /** * Creates a mock AgentService diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts index d351054ca2fd89..4037f1a7cbc464 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts @@ -8,6 +8,7 @@ import { IRouter, Logger, RequestHandlerContext } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; import { schema } from '@kbn/config-schema'; +import { metadataIndexPattern } from '../../../../common/endpoint/constants'; import { getESQueryHostMetadataByID, kibanaRequestToMetadataListESQuery } from './query_builders'; import { HostInfo, @@ -67,13 +68,10 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp }, async (context, req, res) => { try { - const index = await endpointAppContext.service - .getIndexPatternRetriever() - .getMetadataIndexPattern(context); const queryParams = await kibanaRequestToMetadataListESQuery( req, endpointAppContext, - index + metadataIndexPattern ); const response = (await context.core.elasticsearch.legacy.client.callAsCurrentUser( 'search', @@ -125,10 +123,7 @@ export async function getHostData( metadataRequestContext: MetadataRequestContext, id: string ): Promise { - const index = await metadataRequestContext.endpointAppContext.service - .getIndexPatternRetriever() - .getMetadataIndexPattern(metadataRequestContext.requestHandlerContext); - const query = getESQueryHostMetadataByID(id, index); + const query = getESQueryHostMetadataByID(id, metadataIndexPattern); const response = (await metadataRequestContext.requestHandlerContext.core.elasticsearch.legacy.client.callAsCurrentUser( 'search', query diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts index 9b9d4a74e5970c..80626bbdb6e7fc 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts @@ -27,11 +27,7 @@ import { } from '../../../../common/endpoint/types'; import { SearchResponse } from 'elasticsearch'; import { registerEndpointRoutes } from './index'; -import { - createMockAgentService, - createMockMetadataIndexPatternRetriever, - createRouteHandlerContext, -} from '../../mocks'; +import { createMockAgentService, createRouteHandlerContext } from '../../mocks'; import { AgentService } from '../../../../../ingest_manager/server'; import Boom from 'boom'; import { EndpointAppContextService } from '../../endpoint_app_context_services'; @@ -63,7 +59,6 @@ describe('test endpoint route', () => { mockAgentService = createMockAgentService(); endpointAppContextService = new EndpointAppContextService(); endpointAppContextService.start({ - indexPatternRetriever: createMockMetadataIndexPatternRetriever(), agentService: mockAgentService, }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts index 7fa5a8b13db3dd..9e9eaafd0f1dea 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts @@ -5,9 +5,9 @@ */ import { httpServerMock, loggingServiceMock } from '../../../../../../../src/core/server/mocks'; import { kibanaRequestToMetadataListESQuery, getESQueryHostMetadataByID } from './query_builders'; -import { MetadataIndexPattern } from '../../mocks'; import { EndpointAppContextService } from '../../endpoint_app_context_services'; import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__'; +import { metadataIndexPattern } from '../../../../common/endpoint/constants'; describe('query builder', () => { describe('MetadataListESQuery', () => { @@ -22,7 +22,7 @@ describe('query builder', () => { service: new EndpointAppContextService(), config: () => Promise.resolve(createMockConfig()), }, - MetadataIndexPattern + metadataIndexPattern ); expect(query).toEqual({ body: { @@ -54,7 +54,7 @@ describe('query builder', () => { }, from: 0, size: 10, - index: MetadataIndexPattern, + index: metadataIndexPattern, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record); }); @@ -74,7 +74,7 @@ describe('query builder', () => { service: new EndpointAppContextService(), config: () => Promise.resolve(createMockConfig()), }, - MetadataIndexPattern + metadataIndexPattern ); expect(query).toEqual({ body: { @@ -119,7 +119,7 @@ describe('query builder', () => { }, from: 0, size: 10, - index: MetadataIndexPattern, + index: metadataIndexPattern, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record); }); @@ -128,7 +128,7 @@ describe('query builder', () => { describe('MetadataGetQuery', () => { it('searches for the correct ID', () => { const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899'; - const query = getESQueryHostMetadataByID(mockID, MetadataIndexPattern); + const query = getESQueryHostMetadataByID(mockID, metadataIndexPattern); expect(query).toEqual({ body: { @@ -136,7 +136,7 @@ describe('query builder', () => { sort: [{ 'event.created': { order: 'desc' } }], size: 1, }, - index: MetadataIndexPattern, + index: metadataIndexPattern, }); }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts index 25bf2c45aa4218..2b94fe3576e2dc 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { EndpointAppContextService } from '../../endpoint_app_context_services'; -import { - createMockAgentService, - createMockIndexPatternRetriever, - createRouteHandlerContext, -} from '../../mocks'; +import { createMockAgentService, createRouteHandlerContext } from '../../mocks'; import { getHostPolicyResponseHandler } from './handlers'; import { IScopedClusterClient, @@ -41,7 +37,6 @@ describe('test policy response handler', () => { endpointAppContextService = new EndpointAppContextService(); mockAgentService = createMockAgentService(); endpointAppContextService.start({ - indexPatternRetriever: createMockIndexPatternRetriever('metrics-endpoint-policy-*'), agentService: mockAgentService, }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.ts index beb76a8051c357..fd685efb94aaa5 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.ts @@ -5,6 +5,7 @@ */ import { RequestHandler } from 'kibana/server'; import { TypeOf } from '@kbn/config-schema'; +import { policyIndexPattern } from '../../../../common/endpoint/constants'; import { GetPolicyResponseSchema } from '../../../../common/endpoint/schema/policy'; import { EndpointAppContext } from '../../types'; import { getPolicyResponseByHostId } from './service'; @@ -14,12 +15,8 @@ export const getHostPolicyResponseHandler = function ( ): RequestHandler, undefined> { return async (context, request, response) => { try { - const index = await endpointAppContext.service - .getIndexPatternRetriever() - .getPolicyResponseIndexPattern(context); - const doc = await getPolicyResponseByHostId( - index, + policyIndexPattern, request.query.hostId, context.core.elasticsearch.legacy.client ); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/ancestry.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/ancestry.ts index af3fe8d434cbc2..aa040638045b2c 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/ancestry.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/ancestry.ts @@ -6,6 +6,7 @@ import { RequestHandler, Logger } from 'kibana/server'; import { TypeOf } from '@kbn/config-schema'; +import { eventsIndexPattern } from '../../../../common/endpoint/constants'; import { validateAncestry } from '../../../../common/endpoint/schema/resolver'; import { Fetcher } from './utils/fetch'; import { EndpointAppContext } from '../../types'; @@ -20,12 +21,9 @@ export function handleAncestry( query: { ancestors, legacyEndpointID: endpointID }, } = req; try { - const indexRetriever = endpointAppContext.service.getIndexPatternRetriever(); - const client = context.core.elasticsearch.legacy.client; - const indexPattern = await indexRetriever.getEventIndexPattern(context); - const fetcher = new Fetcher(client, id, indexPattern, endpointID); + const fetcher = new Fetcher(client, id, eventsIndexPattern, endpointID); const ancestorInfo = await fetcher.ancestors(ancestors); return res.ok({ diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/children.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/children.ts index a8156e9729579e..83aed602c97a33 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/children.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/children.ts @@ -6,6 +6,7 @@ import { RequestHandler, Logger } from 'kibana/server'; import { TypeOf } from '@kbn/config-schema'; +import { eventsIndexPattern } from '../../../../common/endpoint/constants'; import { validateChildren } from '../../../../common/endpoint/schema/resolver'; import { Fetcher } from './utils/fetch'; import { EndpointAppContext } from '../../types'; @@ -20,11 +21,8 @@ export function handleChildren( query: { children, generations, afterChild, legacyEndpointID: endpointID }, } = req; try { - const indexRetriever = endpointAppContext.service.getIndexPatternRetriever(); - const indexPattern = await indexRetriever.getEventIndexPattern(context); - const client = context.core.elasticsearch.legacy.client; - const fetcher = new Fetcher(client, id, indexPattern, endpointID); + const fetcher = new Fetcher(client, id, eventsIndexPattern, endpointID); return res.ok({ body: await fetcher.children(children, generations, afterChild), diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/events.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/events.ts index f739f9a1ca2e6a..5018a265cd12d8 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/events.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/events.ts @@ -6,6 +6,7 @@ import { TypeOf } from '@kbn/config-schema'; import { RequestHandler, Logger } from 'kibana/server'; +import { eventsIndexPattern } from '../../../../common/endpoint/constants'; import { validateEvents } from '../../../../common/endpoint/schema/resolver'; import { Fetcher } from './utils/fetch'; import { EndpointAppContext } from '../../types'; @@ -20,11 +21,9 @@ export function handleEvents( query: { events, afterEvent, legacyEndpointID: endpointID }, } = req; try { - const indexRetriever = endpointAppContext.service.getIndexPatternRetriever(); const client = context.core.elasticsearch.legacy.client; - const indexPattern = await indexRetriever.getEventIndexPattern(context); - const fetcher = new Fetcher(client, id, indexPattern, endpointID); + const fetcher = new Fetcher(client, id, eventsIndexPattern, endpointID); return res.ok({ body: await fetcher.events(events, afterEvent), diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree.ts index baad56c74b8a86..cad6d948358084 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree.ts @@ -6,6 +6,7 @@ import { RequestHandler, Logger } from 'kibana/server'; import { TypeOf } from '@kbn/config-schema'; +import { eventsIndexPattern } from '../../../../common/endpoint/constants'; import { validateTree } from '../../../../common/endpoint/schema/resolver'; import { Fetcher } from './utils/fetch'; import { Tree } from './utils/tree'; @@ -32,10 +33,8 @@ export function handleTree( } = req; try { const client = context.core.elasticsearch.legacy.client; - const indexRetriever = endpointAppContext.service.getIndexPatternRetriever(); - const indexPattern = await indexRetriever.getEventIndexPattern(context); - const fetcher = new Fetcher(client, id, indexPattern, endpointID); + const fetcher = new Fetcher(client, id, eventsIndexPattern, endpointID); const [childrenNodes, ancestry, relatedEvents, relatedAlerts] = await Promise.all([ fetcher.children(children, generations, afterChild), diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index ebb2310ac53104..9fe7307e8cb6da 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -43,7 +43,6 @@ import { registerAlertRoutes } from './endpoint/alerts/routes'; import { registerPolicyRoutes } from './endpoint/routes/policy'; import { EndpointAppContextService } from './endpoint/endpoint_app_context_services'; import { EndpointAppContext } from './endpoint/types'; -import { IngestIndexPatternRetriever } from './endpoint/alerts/index_pattern'; export interface SetupPlugins { alerts: AlertingSetup; @@ -219,10 +218,6 @@ export class Plugin implements IPlugin { - it('should retrieve the index pattern for events', async () => { - const { body } = await supertest.get('/api/endpoint/index_pattern/events').expect(200); - expect(body.indexPattern).to.eql('events-endpoint-*'); - }); - - it('should retrieve the index pattern for metadata', async () => { - const { body } = await supertest.get('/api/endpoint/index_pattern/metadata').expect(200); - expect(body.indexPattern).to.eql('metrics-endpoint.metadata-*'); - }); - - it('should retrieve the index pattern for policy', async () => { - const { body } = await supertest.get('/api/endpoint/index_pattern/policy').expect(200); - expect(body.indexPattern).to.eql('metrics-endpoint.policy-*'); - }); - - it('should not retrieve the index pattern for an invalid key', async () => { - await supertest.get('/api/endpoint/index_pattern/blah').expect(404); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/endpoint/data_stream_helper.ts b/x-pack/test/api_integration/apis/endpoint/data_stream_helper.ts index bb8fbd4f296f80..8ab08ff501f5bd 100644 --- a/x-pack/test/api_integration/apis/endpoint/data_stream_helper.ts +++ b/x-pack/test/api_integration/apis/endpoint/data_stream_helper.ts @@ -5,6 +5,11 @@ */ import { Client } from '@elastic/elasticsearch'; +import { + metadataIndexPattern, + eventsIndexPattern, + policyIndexPattern, +} from '../../../../plugins/security_solution/common/endpoint/constants'; export async function deleteDataStream(getService: (serviceName: 'es') => Client, index: string) { const client = getService('es'); @@ -20,13 +25,13 @@ export async function deleteDataStream(getService: (serviceName: 'es') => Client } export async function deleteMetadataStream(getService: (serviceName: 'es') => Client) { - await deleteDataStream(getService, 'metrics-endpoint.metadata-*'); + await deleteDataStream(getService, metadataIndexPattern); } export async function deleteEventsStream(getService: (serviceName: 'es') => Client) { - await deleteDataStream(getService, 'events-endpoint-*'); + await deleteDataStream(getService, eventsIndexPattern); } export async function deletePolicyStream(getService: (serviceName: 'es') => Client) { - await deleteDataStream(getService, 'metrics-endpoint.policy-*'); + await deleteDataStream(getService, policyIndexPattern); } diff --git a/x-pack/test/api_integration/apis/endpoint/index.ts b/x-pack/test/api_integration/apis/endpoint/index.ts index f437f9a7472fb5..d3090e113324f7 100644 --- a/x-pack/test/api_integration/apis/endpoint/index.ts +++ b/x-pack/test/api_integration/apis/endpoint/index.ts @@ -3,7 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - import { FtrProviderContext } from '../../ftr_provider_context'; export default function endpointAPIIntegrationTests({ @@ -16,7 +15,6 @@ export default function endpointAPIIntegrationTests({ before(async () => { await ingestManager.setup(); }); - loadTestFile(require.resolve('./alerts/index_pattern')); loadTestFile(require.resolve('./resolver')); loadTestFile(require.resolve('./metadata')); loadTestFile(require.resolve('./alerts')); diff --git a/x-pack/test/endpoint_api_integration_no_ingest/apis/alerts/index.ts b/x-pack/test/endpoint_api_integration_no_ingest/apis/alerts/index.ts index 7e092ba2b85b55..5c14bc899451ef 100644 --- a/x-pack/test/endpoint_api_integration_no_ingest/apis/alerts/index.ts +++ b/x-pack/test/endpoint_api_integration_no_ingest/apis/alerts/index.ts @@ -20,7 +20,7 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.unload('endpoint/alerts/host_api_feature'); }); - it('should return a 500', async () => { + it('should not return data', async () => { await supertest.get('/api/endpoint/alerts').expect(500); }); }); diff --git a/x-pack/test/endpoint_api_integration_no_ingest/apis/alerts/index_pattern.ts b/x-pack/test/endpoint_api_integration_no_ingest/apis/alerts/index_pattern.ts deleted file mode 100644 index faea56961b5108..00000000000000 --- a/x-pack/test/endpoint_api_integration_no_ingest/apis/alerts/index_pattern.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; - * you may not use this file except in compliance with the Elastic License. - */ -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); - - describe('Endpoint index pattern API without ingest manager initialized', () => { - it('should not retrieve the index pattern for events', async () => { - await supertest.get('/api/endpoint/index_pattern/events').expect(404); - }); - }); -} diff --git a/x-pack/test/endpoint_api_integration_no_ingest/apis/index.ts b/x-pack/test/endpoint_api_integration_no_ingest/apis/index.ts index ae72a405930457..16e3c55bafe403 100644 --- a/x-pack/test/endpoint_api_integration_no_ingest/apis/index.ts +++ b/x-pack/test/endpoint_api_integration_no_ingest/apis/index.ts @@ -9,7 +9,6 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function endpointAPIIntegrationTests({ loadTestFile }: FtrProviderContext) { describe('Endpoint plugin', function () { this.tags('ciGroup7'); - loadTestFile(require.resolve('./alerts/index_pattern')); loadTestFile(require.resolve('./metadata')); loadTestFile(require.resolve('./alerts')); }); diff --git a/x-pack/test/endpoint_api_integration_no_ingest/apis/metadata.ts b/x-pack/test/endpoint_api_integration_no_ingest/apis/metadata.ts index 3802060e6fc0df..da77a9d3bba1cf 100644 --- a/x-pack/test/endpoint_api_integration_no_ingest/apis/metadata.ts +++ b/x-pack/test/endpoint_api_integration_no_ingest/apis/metadata.ts @@ -11,7 +11,7 @@ export default function ({ getService }: FtrProviderContext) { describe('test metadata api when ingest manager is not initialized', () => { before(async () => await esArchiver.load('endpoint/metadata/api_feature')); after(async () => await esArchiver.unload('endpoint/metadata/api_feature')); - it('metadata api should return a 500', async () => { + it('metadata api should not return results', async () => { await supertest.post('/api/endpoint/metadata').set('kbn-xsrf', 'xxx').send().expect(500); }); }); From 4d02eab0f3b42cc15e30fe09a9d2f83918fa11a4 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Mon, 15 Jun 2020 14:25:53 -0500 Subject: [PATCH 2/3] Updates the Release Notes content in CONTRIBUTING (#69032) * Updates the Release Notes content in CONTRIBUTING * Release Notes guidelines * Fixes bulleted list indentation --- CONTRIBUTING.md | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 959c12af904631..a7345f4b2897b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -657,8 +657,8 @@ Distributable packages can be found in `target/` after the build completes. Kibana documentation is written in [asciidoc](http://asciidoc.org/) format in the `docs/` directory. -To build the docs, you must clone the [elastic/docs](https://github.com/elastic/docs) -repo as a sibling of your kibana repo. Follow the instructions in that project's +To build the docs, clone the [elastic/docs](https://github.com/elastic/docs) +repo as a sibling of your Kibana repo. Follow the instructions in that project's README for getting the docs tooling set up. **To build the Kibana docs and open them in your browser:** @@ -676,14 +676,26 @@ node scripts/docs.js --open Part of this process only applies to maintainers, since it requires access to GitHub labels. -Kibana publishes [Release Notes](https://www.elastic.co/guide/en/kibana/current/release-notes.html) for major and minor releases. To generate the Release Notes, the writers run a script against this repo to collect the merged PRs against the release. -To include your PRs in the Release Notes: +Kibana publishes [Release Notes](https://www.elastic.co/guide/en/kibana/current/release-notes.html) for major and minor releases. The Release Notes summarize what the PRs accomplish in language that is meaningful to users. To generate the Release Notes, the team runs a script against this repo to collect the merged PRs against the release. -1. In the title, summarize what the PR accomplishes in language that is meaningful to the user. In general, use present tense (for example, Adds, Fixes) in sentence case. -2. Label the PR with the targeted version (ex: `v7.3.0`). -3. Label the PR with the appropriate GitHub labels: +#### Create the Release Notes text +The text that appears in the Release Notes is pulled directly from your PR title, or a single paragraph of text that you specify in the PR description. + +To use a single paragraph of text, enter `Release note:` or a `## Release note` header in the PR description, followed by your text. For example, refer to this [PR](https://github.com/elastic/kibana/pull/65796) that uses the `## Release note` header. + +When you create the Release Notes text, use the following best practices: +* Use present tense. +* Use sentence case. +* When you create a feature PR, start with `Adds`. +* When you create an enhancement PR, start with `Improves`. +* When you create a bug fix PR, start with `Fixes`. +* When you create a deprecation PR, start with `Deprecates`. + +#### Add your labels +1. Label the PR with the targeted version (ex: `v7.3.0`). +2. Label the PR with the appropriate GitHub labels: * For a new feature or functionality, use `release_note:enhancement`. - * For an external-facing fix, use `release_note:fix`. Exception: docs, build, and test fixes do not go in the Release Notes. Neither fixes for issues that were only on `master` and never have been released. + * For an external-facing fix, use `release_note:fix`. We do not include docs, build, and test fixes in the Release Notes, or unreleased issues that are only on `master`. * For a deprecated feature, use `release_note:deprecation`. * For a breaking change, use `release_note:breaking`. * To **NOT** include your changes in the Release Notes, use `release_note:skip`. @@ -695,7 +707,7 @@ We also produce a blog post that details more important breaking API changes in ## Name the feature with the break (ex: Visualize Loader) -Summary of the change. Anything Under `#Dev Docs` will be used in the blog. +Summary of the change. Anything Under `#Dev Docs` is used in the blog. ``` ## Signing the contributor license agreement From a7900d0e994611ca751e2e60bd5708ffc5b04e34 Mon Sep 17 00:00:00 2001 From: Josh Dover Date: Mon, 15 Jun 2020 13:31:02 -0600 Subject: [PATCH 3/3] Fix plugin lifecycle log to only include server plugins (#68686) Co-authored-by: Elastic Machine --- .../server/plugins/plugins_system.test.ts | 32 +++++++++++++++++++ src/core/server/plugins/plugins_system.ts | 17 +++++----- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/core/server/plugins/plugins_system.test.ts b/src/core/server/plugins/plugins_system.test.ts index 8b318ad1b735eb..70983e4fd087b5 100644 --- a/src/core/server/plugins/plugins_system.test.ts +++ b/src/core/server/plugins/plugins_system.test.ts @@ -34,6 +34,7 @@ import { PluginWrapper } from './plugin'; import { PluginName } from './types'; import { PluginsSystem } from './plugins_system'; import { coreMock } from '../mocks'; +import { Logger } from '../logging'; const logger = loggingServiceMock.create(); function createPlugin( @@ -435,6 +436,21 @@ describe('setup', () => { `[Error: Setup lifecycle of "timeout-setup" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.]` ); }); + + it('logs only server-side plugins', async () => { + [ + createPlugin('order-0'), + createPlugin('order-not-run', { server: false }), + createPlugin('order-1'), + ].forEach((plugin, index) => { + jest.spyOn(plugin, 'setup').mockResolvedValue(`setup-as-${index}`); + jest.spyOn(plugin, 'start').mockResolvedValue(`started-as-${index}`); + pluginsSystem.addPlugin(plugin); + }); + await pluginsSystem.setupPlugins(setupDeps); + const log = logger.get.mock.results[0].value as jest.Mocked; + expect(log.info).toHaveBeenCalledWith(`Setting up [2] plugins: [order-1,order-0]`); + }); }); describe('start', () => { @@ -461,4 +477,20 @@ describe('start', () => { `[Error: Start lifecycle of "timeout-start" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.]` ); }); + + it('logs only server-side plugins', async () => { + [ + createPlugin('order-0'), + createPlugin('order-not-run', { server: false }), + createPlugin('order-1'), + ].forEach((plugin, index) => { + jest.spyOn(plugin, 'setup').mockResolvedValue(`setup-as-${index}`); + jest.spyOn(plugin, 'start').mockResolvedValue(`started-as-${index}`); + pluginsSystem.addPlugin(plugin); + }); + await pluginsSystem.setupPlugins(setupDeps); + await pluginsSystem.startPlugins(startDeps); + const log = logger.get.mock.results[0].value as jest.Mocked; + expect(log.info).toHaveBeenCalledWith(`Starting [2] plugins: [order-1,order-0]`); + }); }); diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index e0401006ffac96..1bf1f4b189a676 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -66,15 +66,16 @@ export class PluginsSystem { return contracts; } - const sortedPlugins = this.getTopologicallySortedPluginNames(); - this.log.info(`Setting up [${this.plugins.size}] plugins: [${[...sortedPlugins]}]`); - - for (const pluginName of sortedPlugins) { - const plugin = this.plugins.get(pluginName)!; - if (!plugin.includesServerPlugin) { - continue; - } + const sortedPlugins = new Map( + [...this.getTopologicallySortedPluginNames()] + .map((pluginName) => [pluginName, this.plugins.get(pluginName)!] as [string, PluginWrapper]) + .filter(([pluginName, plugin]) => plugin.includesServerPlugin) + ); + this.log.info( + `Setting up [${sortedPlugins.size}] plugins: [${[...sortedPlugins.keys()].join(',')}]` + ); + for (const [pluginName, plugin] of sortedPlugins) { this.log.debug(`Setting up plugin "${pluginName}"...`); const pluginDeps = new Set([...plugin.requiredPlugins, ...plugin.optionalPlugins]); const pluginDepContracts = Array.from(pluginDeps).reduce((depContracts, dependencyName) => {