From 7fdc34762c5127ae560029a5de5a9e5d7e306c2c Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Tue, 23 Mar 2021 11:47:47 +0100 Subject: [PATCH 01/38] extract http_tools to package --- package.json | 1 + packages/kbn-http-tools/README.md | 3 + packages/kbn-http-tools/jest.config.js | 13 + packages/kbn-http-tools/package.json | 19 ++ packages/kbn-http-tools/src/create_server.ts | 29 ++ .../default_validation_error_handler.test.ts | 51 ++++ .../src/default_validation_error_handler.ts | 63 ++++ .../src/get_listener_options.ts | 21 ++ .../kbn-http-tools/src/get_request_id.test.ts | 85 ++++++ packages/kbn-http-tools/src/get_request_id.ts | 22 ++ .../src/get_server_options.test.ts | 122 ++++++++ .../kbn-http-tools/src/get_server_options.ts | 85 ++++++ packages/kbn-http-tools/src/index.ts | 14 + packages/kbn-http-tools/src/types.ts | 37 +++ packages/kbn-http-tools/tsconfig.json | 14 + .../server/http/base_path_proxy_server.ts | 4 +- src/core/server/http/http_server.ts | 2 +- src/core/server/http/http_tools.test.ts | 274 ------------------ src/core/server/http/http_tools.ts | 186 ------------ src/core/server/http/https_redirect_server.ts | 2 +- .../http/integration_tests/router.test.ts | 55 +++- src/core/server/http/ssl_config.ts | 13 +- yarn.lock | 4 + 23 files changed, 643 insertions(+), 476 deletions(-) create mode 100644 packages/kbn-http-tools/README.md create mode 100644 packages/kbn-http-tools/jest.config.js create mode 100644 packages/kbn-http-tools/package.json create mode 100644 packages/kbn-http-tools/src/create_server.ts create mode 100644 packages/kbn-http-tools/src/default_validation_error_handler.test.ts create mode 100644 packages/kbn-http-tools/src/default_validation_error_handler.ts create mode 100644 packages/kbn-http-tools/src/get_listener_options.ts create mode 100644 packages/kbn-http-tools/src/get_request_id.test.ts create mode 100644 packages/kbn-http-tools/src/get_request_id.ts create mode 100644 packages/kbn-http-tools/src/get_server_options.test.ts create mode 100644 packages/kbn-http-tools/src/get_server_options.ts create mode 100644 packages/kbn-http-tools/src/index.ts create mode 100644 packages/kbn-http-tools/src/types.ts create mode 100644 packages/kbn-http-tools/tsconfig.json delete mode 100644 src/core/server/http/http_tools.test.ts delete mode 100644 src/core/server/http/http_tools.ts diff --git a/package.json b/package.json index 32cf8dc1aee0f3..a34edd2450bc61 100644 --- a/package.json +++ b/package.json @@ -122,6 +122,7 @@ "@kbn/apm-utils": "link:packages/kbn-apm-utils", "@kbn/config": "link:packages/kbn-config", "@kbn/config-schema": "link:packages/kbn-config-schema", + "@kbn/http-tools": "link:packages/kbn-http-tools", "@kbn/i18n": "link:packages/kbn-i18n", "@kbn/interpreter": "link:packages/kbn-interpreter", "@kbn/legacy-logging": "link:packages/kbn-legacy-logging", diff --git a/packages/kbn-http-tools/README.md b/packages/kbn-http-tools/README.md new file mode 100644 index 00000000000000..fd132e4312487f --- /dev/null +++ b/packages/kbn-http-tools/README.md @@ -0,0 +1,3 @@ +# @kbn/utils + +Shared server-side utilities shared across packages and plugins. \ No newline at end of file diff --git a/packages/kbn-http-tools/jest.config.js b/packages/kbn-http-tools/jest.config.js new file mode 100644 index 00000000000000..b0b4cf8897804d --- /dev/null +++ b/packages/kbn-http-tools/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-http-tools'], +}; diff --git a/packages/kbn-http-tools/package.json b/packages/kbn-http-tools/package.json new file mode 100644 index 00000000000000..174ee8d97dfec4 --- /dev/null +++ b/packages/kbn-http-tools/package.json @@ -0,0 +1,19 @@ +{ + "name": "@kbn/http-tools", + "main": "./target/index.js", + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "private": true, + "scripts": { + "build": "rm -rf target && ../../node_modules/.bin/tsc", + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" + }, + "dependencies": { + "@kbn/config-schema": "link:../kbn-config-schema", + "@kbn/std": "link:../kbn-std" + }, + "devDependencies": { + "@kbn/utility-types": "link:../kbn-utility-types" + } +} \ No newline at end of file diff --git a/packages/kbn-http-tools/src/create_server.ts b/packages/kbn-http-tools/src/create_server.ts new file mode 100644 index 00000000000000..4752e342d5d3e3 --- /dev/null +++ b/packages/kbn-http-tools/src/create_server.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Server, ServerOptions } from '@hapi/hapi'; +import { ListenerOptions } from './get_listener_options'; + +export function createServer(serverOptions: ServerOptions, listenerOptions: ListenerOptions) { + const server = new Server(serverOptions); + + server.listener.keepAliveTimeout = listenerOptions.keepaliveTimeout; + server.listener.setTimeout(listenerOptions.socketTimeout); + server.listener.on('timeout', (socket) => { + socket.destroy(); + }); + server.listener.on('clientError', (err, socket) => { + if (socket.writable) { + socket.end(Buffer.from('HTTP/1.1 400 Bad Request\r\n\r\n', 'ascii')); + } else { + socket.destroy(err); + } + }); + + return server; +} diff --git a/packages/kbn-http-tools/src/default_validation_error_handler.test.ts b/packages/kbn-http-tools/src/default_validation_error_handler.test.ts new file mode 100644 index 00000000000000..93b09ef13e0307 --- /dev/null +++ b/packages/kbn-http-tools/src/default_validation_error_handler.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Joi from 'joi'; +import { Request, ResponseToolkit } from '@hapi/hapi'; +import { + defaultValidationErrorHandler, + HapiValidationError, +} from './default_validation_error_handler'; + +const emptyOutput = { + statusCode: 400, + headers: {}, + payload: { + statusCode: 400, + error: '', + validation: { + source: '', + keys: [], + }, + }, +}; + +describe('defaultValidationErrorHandler', () => { + it('formats value validation errors correctly', () => { + expect.assertions(1); + const schema = Joi.array().items( + Joi.object({ + type: Joi.string().required(), + }).required() + ); + + const error = schema.validate([{}], { abortEarly: false }).error as HapiValidationError; + + // Emulate what Hapi v17 does by default + error.output = { ...emptyOutput }; + error.output.payload.validation.keys = ['0.type', '']; + + try { + defaultValidationErrorHandler({} as Request, {} as ResponseToolkit, error); + } catch (err) { + // Verify the empty string gets corrected to 'value' + expect(err.output.payload.validation.keys).toEqual(['0.type', 'value']); + } + }); +}); diff --git a/packages/kbn-http-tools/src/default_validation_error_handler.ts b/packages/kbn-http-tools/src/default_validation_error_handler.ts new file mode 100644 index 00000000000000..d2f4e993f3e4b2 --- /dev/null +++ b/packages/kbn-http-tools/src/default_validation_error_handler.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Lifecycle, Request, ResponseToolkit, Util } from '@hapi/hapi'; +import { ValidationError } from 'joi'; +import Hoek from '@hapi/hoek'; + +/** + * Hapi extends the ValidationError interface to add this output key with more data. + */ +export interface HapiValidationError extends ValidationError { + output: { + statusCode: number; + headers: Util.Dictionary; + payload: { + statusCode: number; + error: string; + message?: string; + validation: { + source: string; + keys: string[]; + }; + }; + }; +} + +/** + * Used to replicate Hapi v16 and below's validation responses. Should be used in the routes.validate.failAction key. + */ +export function defaultValidationErrorHandler( + request: Request, + h: ResponseToolkit, + err?: Error +): Lifecycle.ReturnValue { + // Newer versions of Joi don't format the key for missing params the same way. This shim + // provides backwards compatibility. Unfortunately, Joi doesn't export it's own Error class + // in JS so we have to rely on the `name` key before we can cast it. + // + // The Hapi code we're 'overwriting' can be found here: + // https://github.com/hapijs/hapi/blob/master/lib/validation.js#L102 + if (err && err.name === 'ValidationError' && err.hasOwnProperty('output')) { + const validationError: HapiValidationError = err as HapiValidationError; + const validationKeys: string[] = []; + + validationError.details.forEach((detail) => { + if (detail.path.length > 0) { + validationKeys.push(Hoek.escapeHtml(detail.path.join('.'))); + } else { + // If no path, use the value sigil to signal the entire value had an issue. + validationKeys.push('value'); + } + }); + + validationError.output.payload.validation.keys = validationKeys; + } + + throw err; +} diff --git a/packages/kbn-http-tools/src/get_listener_options.ts b/packages/kbn-http-tools/src/get_listener_options.ts new file mode 100644 index 00000000000000..00884312b599fb --- /dev/null +++ b/packages/kbn-http-tools/src/get_listener_options.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { IHttpConfig } from './types'; + +export interface ListenerOptions { + keepaliveTimeout: number; + socketTimeout: number; +} + +export function getListenerOptions(config: IHttpConfig): ListenerOptions { + return { + keepaliveTimeout: config.keepaliveTimeout, + socketTimeout: config.socketTimeout, + }; +} diff --git a/packages/kbn-http-tools/src/get_request_id.test.ts b/packages/kbn-http-tools/src/get_request_id.test.ts new file mode 100644 index 00000000000000..d0dc8a0085c9a8 --- /dev/null +++ b/packages/kbn-http-tools/src/get_request_id.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { getRequestId } from './get_request_id'; + +jest.mock('uuid', () => ({ + v4: jest.fn().mockReturnValue('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'), +})); + +describe('getRequestId', () => { + describe('when allowFromAnyIp is true', () => { + it('generates a UUID if no x-opaque-id header is present', () => { + const request = { + headers: {}, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + ); + }); + + it('uses x-opaque-id header value if present', () => { + const request = { + headers: { + 'x-opaque-id': 'id from header', + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( + 'id from header' + ); + }); + }); + + describe('when allowFromAnyIp is false', () => { + describe('and ipAllowlist is empty', () => { + it('generates a UUID even if x-opaque-id header is present', () => { + const request = { + headers: { 'x-opaque-id': 'id from header' }, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: [] })).toEqual( + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + ); + }); + }); + + describe('and ipAllowlist is not empty', () => { + it('uses x-opaque-id header if request comes from trusted IP address', () => { + const request = { + headers: { 'x-opaque-id': 'id from header' }, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( + 'id from header' + ); + }); + + it('generates a UUID if request comes from untrusted IP address', () => { + const request = { + headers: { 'x-opaque-id': 'id from header' }, + raw: { req: { socket: { remoteAddress: '5.5.5.5' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + ); + }); + + it('generates UUID if request comes from trusted IP address but no x-opaque-id header is present', () => { + const request = { + headers: {}, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + ); + }); + }); + }); +}); diff --git a/packages/kbn-http-tools/src/get_request_id.ts b/packages/kbn-http-tools/src/get_request_id.ts new file mode 100644 index 00000000000000..42ae56568b30a5 --- /dev/null +++ b/packages/kbn-http-tools/src/get_request_id.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Request } from '@hapi/hapi'; +import uuid from 'uuid'; + +export function getRequestId( + request: Request, + options: { allowFromAnyIp: boolean; ipAllowlist: string[] } +): string { + return options.allowFromAnyIp || + // socket may be undefined in integration tests that connect via the http listener directly + (request.raw.req.socket?.remoteAddress && + options.ipAllowlist.includes(request.raw.req.socket.remoteAddress)) + ? request.headers['x-opaque-id'] ?? uuid.v4() + : uuid.v4(); +} diff --git a/packages/kbn-http-tools/src/get_server_options.test.ts b/packages/kbn-http-tools/src/get_server_options.test.ts new file mode 100644 index 00000000000000..03fe9268a8db7b --- /dev/null +++ b/packages/kbn-http-tools/src/get_server_options.test.ts @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ByteSizeValue } from '@kbn/config-schema'; +import { getServerOptions } from './get_server_options'; +import { IHttpConfig } from './types'; + +jest.mock('fs', () => { + const original = jest.requireActual('fs'); + return { + // Hapi Inert patches native methods + ...original, + readFileSync: jest.fn(), + }; +}); + +const createConfig = (parts: Partial): IHttpConfig => ({ + host: 'localhost', + port: 5601, + socketTimeout: 120000, + keepaliveTimeout: 120000, + maxPayload: ByteSizeValue.parse('1048576b'), + ...parts, + cors: { + enabled: false, + allowCredentials: false, + allowOrigin: ['*'], + ...parts.cors, + }, + ssl: { + enabled: false, + ...parts.ssl, + }, +}); + +describe('getServerOptions', () => { + beforeEach(() => + jest.requireMock('fs').readFileSync.mockImplementation((path: string) => `content-${path}`) + ); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('properly configures TLS with default options', () => { + const httpConfig = createConfig({ + ssl: { + enabled: true, + key: 'some-key-path', + certificate: 'some-certificate-path', + }, + }); + + expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` + Object { + "ca": undefined, + "cert": "some-certificate-path", + "ciphers": undefined, + "honorCipherOrder": true, + "key": "some-key-path", + "passphrase": undefined, + "rejectUnauthorized": undefined, + "requestCert": undefined, + "secureOptions": undefined, + } + `); + }); + + it('properly configures TLS with client authentication', () => { + const httpConfig = createConfig({ + ssl: { + enabled: true, + key: 'some-key-path', + certificate: 'some-certificate-path', + certificateAuthorities: ['ca-1', 'ca-2'], + cipherSuites: ['suite-a', 'suite-b'], + keyPassphrase: 'passPhrase', + rejectUnauthorized: true, + requestCert: true, + secureOptions: 42, + }, + }); + + expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` + Object { + "ca": Array [ + "ca-1", + "ca-2", + ], + "cert": "some-certificate-path", + "ciphers": "suite-a:suite-b", + "honorCipherOrder": true, + "key": "some-key-path", + "passphrase": "passPhrase", + "rejectUnauthorized": true, + "requestCert": true, + "secureOptions": 42, + } + `); + }); + + it('properly configures CORS when cors enabled', () => { + const httpConfig = createConfig({ + cors: { + enabled: true, + allowCredentials: false, + allowOrigin: ['*'], + }, + }); + + expect(getServerOptions(httpConfig).routes?.cors).toEqual({ + credentials: false, + origin: ['*'], + headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf'], + }); + }); +}); diff --git a/packages/kbn-http-tools/src/get_server_options.ts b/packages/kbn-http-tools/src/get_server_options.ts new file mode 100644 index 00000000000000..25715f636e3fcc --- /dev/null +++ b/packages/kbn-http-tools/src/get_server_options.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { RouteOptionsCors, ServerOptions } from '@hapi/hapi'; +import { ensureNoUnsafeProperties } from '@kbn/std'; +import { ServerOptions as TLSOptions } from 'https'; +import { defaultValidationErrorHandler } from './default_validation_error_handler'; +import { IHttpConfig } from './types'; + +const corsAllowedHeaders = ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf']; + +/** + * Converts Kibana `HttpConfig` into `ServerOptions` that are accepted by the Hapi server. + */ +export function getServerOptions(config: IHttpConfig, { configureTLS = true } = {}) { + const cors: RouteOptionsCors | false = config.cors.enabled + ? { + credentials: config.cors.allowCredentials, + origin: config.cors.allowOrigin, + headers: corsAllowedHeaders, + } + : false; + // Note that all connection options configured here should be exactly the same + // as in the legacy platform server (see `src/legacy/server/http/index`). Any change + // SHOULD BE applied in both places. The only exception is TLS-specific options, + // that are configured only here. + const options: ServerOptions = { + host: config.host, + port: config.port, + routes: { + cache: { + privacy: 'private', + otherwise: 'private, no-cache, no-store, must-revalidate', + }, + cors, + payload: { + maxBytes: config.maxPayload.getValueInBytes(), + }, + validate: { + failAction: defaultValidationErrorHandler, + options: { + abortEarly: false, + }, + // TODO: This payload validation can be removed once the legacy platform is completely removed. + // This is a default payload validation which applies to all LP routes which do not specify their own + // `validate.payload` handler, in order to reduce the likelyhood of prototype pollution vulnerabilities. + // (All NP routes are already required to specify their own validation in order to access the payload) + payload: (value) => Promise.resolve(ensureNoUnsafeProperties(value)), + }, + }, + state: { + strictHeader: false, + isHttpOnly: true, + isSameSite: false, // necessary to allow using Kibana inside an iframe + }, + }; + + if (configureTLS && config.ssl.enabled) { + const ssl = config.ssl; + + // TODO: Hapi types have a typo in `tls` property type definition: `https.RequestOptions` is used instead of + // `https.ServerOptions`, and `honorCipherOrder` isn't presented in `https.RequestOptions`. + const tlsOptions: TLSOptions = { + ca: ssl.certificateAuthorities, + cert: ssl.certificate, + ciphers: config.ssl.cipherSuites?.join(':'), + // We use the server's cipher order rather than the client's to prevent the BEAST attack. + honorCipherOrder: true, + key: ssl.key, + passphrase: ssl.keyPassphrase, + secureOptions: ssl.secureOptions, + requestCert: ssl.requestCert, + rejectUnauthorized: ssl.rejectUnauthorized, + }; + + options.tls = tlsOptions; + } + + return options; +} diff --git a/packages/kbn-http-tools/src/index.ts b/packages/kbn-http-tools/src/index.ts new file mode 100644 index 00000000000000..db52bfb2809633 --- /dev/null +++ b/packages/kbn-http-tools/src/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { IHttpConfig, ISslConfig, ICorsConfig } from './types'; +export { createServer } from './create_server'; +export { defaultValidationErrorHandler } from './default_validation_error_handler'; +export { getListenerOptions } from './get_listener_options'; +export { getServerOptions } from './get_server_options'; +export { getRequestId } from './get_request_id'; diff --git a/packages/kbn-http-tools/src/types.ts b/packages/kbn-http-tools/src/types.ts new file mode 100644 index 00000000000000..97a1c595820e55 --- /dev/null +++ b/packages/kbn-http-tools/src/types.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ByteSizeValue } from '@kbn/config-schema'; + +export interface IHttpConfig { + host: string; + port: number; + maxPayload: ByteSizeValue; + keepaliveTimeout: number; + socketTimeout: number; + cors: ICorsConfig; + ssl: ISslConfig; +} + +export interface ICorsConfig { + enabled: boolean; + allowCredentials: boolean; + allowOrigin: string[]; +} + +export interface ISslConfig { + enabled: boolean; + key?: string; + certificate?: string; + certificateAuthorities?: string[]; + cipherSuites?: string[]; + keyPassphrase?: string; + requestCert?: boolean; + rejectUnauthorized?: boolean; + secureOptions?: number; +} diff --git a/packages/kbn-http-tools/tsconfig.json b/packages/kbn-http-tools/tsconfig.json new file mode 100644 index 00000000000000..ec84b963aed700 --- /dev/null +++ b/packages/kbn-http-tools/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target", + "declaration": true, + "declarationMap": true + }, + "include": [ + "src/**/*" + ], + "dependencies": { + "@kbn/std": "link:../kbn-std" + } +} diff --git a/src/core/server/http/base_path_proxy_server.ts b/src/core/server/http/base_path_proxy_server.ts index a5ed0271893937..7db6c93c8ec238 100644 --- a/src/core/server/http/base_path_proxy_server.ts +++ b/src/core/server/http/base_path_proxy_server.ts @@ -10,17 +10,17 @@ import Url from 'url'; import { Agent as HttpsAgent, ServerOptions as TlsOptions } from 'https'; import apm from 'elastic-apm-node'; -import { ByteSizeValue } from '@kbn/config-schema'; import { Server, Request } from '@hapi/hapi'; import HapiProxy from '@hapi/h2o2'; import { sampleSize } from 'lodash'; import * as Rx from 'rxjs'; import { take } from 'rxjs/operators'; +import { ByteSizeValue } from '@kbn/config-schema'; +import { createServer, getListenerOptions, getServerOptions } from '@kbn/http-tools'; import { DevConfig } from '../dev'; import { Logger } from '../logging'; import { HttpConfig } from './http_config'; -import { createServer, getListenerOptions, getServerOptions } from './http_tools'; const alphabet = 'abcdefghijklmnopqrztuvwxyz'.split(''); diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index b0510bc414bf83..a6dc92cf229b15 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -10,10 +10,10 @@ import { Server, Request } from '@hapi/hapi'; import HapiStaticFiles from '@hapi/inert'; import url from 'url'; import uuid from 'uuid'; +import { createServer, getListenerOptions, getServerOptions, getRequestId } from '@kbn/http-tools'; import { Logger, LoggerFactory } from '../logging'; import { HttpConfig } from './http_config'; -import { createServer, getListenerOptions, getServerOptions, getRequestId } from './http_tools'; import { adoptToHapiAuthFormat, AuthenticationHandler } from './lifecycle/auth'; import { adoptToHapiOnPreAuth, OnPreAuthHandler } from './lifecycle/on_pre_auth'; import { adoptToHapiOnPostAuthFormat, OnPostAuthHandler } from './lifecycle/on_post_auth'; diff --git a/src/core/server/http/http_tools.test.ts b/src/core/server/http/http_tools.test.ts deleted file mode 100644 index c2fa3816324fc4..00000000000000 --- a/src/core/server/http/http_tools.test.ts +++ /dev/null @@ -1,274 +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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -jest.mock('fs', () => { - const original = jest.requireActual('fs'); - return { - // Hapi Inert patches native methods - ...original, - readFileSync: jest.fn(), - }; -}); - -jest.mock('uuid', () => ({ - v4: jest.fn().mockReturnValue('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'), -})); - -import supertest from 'supertest'; -import { Request, ResponseToolkit } from '@hapi/hapi'; -import Joi from 'joi'; - -import { - defaultValidationErrorHandler, - HapiValidationError, - getServerOptions, - getRequestId, -} from './http_tools'; -import { HttpServer } from './http_server'; -import { HttpConfig, config } from './http_config'; -import { Router } from './router'; -import { loggingSystemMock } from '../logging/logging_system.mock'; -import { ByteSizeValue } from '@kbn/config-schema'; - -const emptyOutput = { - statusCode: 400, - headers: {}, - payload: { - statusCode: 400, - error: '', - validation: { - source: '', - keys: [], - }, - }, -}; - -afterEach(() => jest.clearAllMocks()); - -describe('defaultValidationErrorHandler', () => { - it('formats value validation errors correctly', () => { - expect.assertions(1); - const schema = Joi.array().items( - Joi.object({ - type: Joi.string().required(), - }).required() - ); - - const error = schema.validate([{}], { abortEarly: false }).error as HapiValidationError; - - // Emulate what Hapi v17 does by default - error.output = { ...emptyOutput }; - error.output.payload.validation.keys = ['0.type', '']; - - try { - defaultValidationErrorHandler({} as Request, {} as ResponseToolkit, error); - } catch (err) { - // Verify the empty string gets corrected to 'value' - expect(err.output.payload.validation.keys).toEqual(['0.type', 'value']); - } - }); -}); - -describe('timeouts', () => { - const logger = loggingSystemMock.create(); - const server = new HttpServer(logger, 'foo'); - const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, {}); - - test('closes sockets on timeout', async () => { - const router = new Router('', logger.get(), enhanceWithContext); - router.get({ path: '/a', validate: false }, async (context, req, res) => { - await new Promise((resolve) => setTimeout(resolve, 2000)); - return res.ok({}); - }); - router.get({ path: '/b', validate: false }, (context, req, res) => res.ok({})); - const { registerRouter, server: innerServer } = await server.setup({ - socketTimeout: 1000, - host: '127.0.0.1', - maxPayload: new ByteSizeValue(1024), - ssl: {}, - cors: { - enabled: false, - }, - compression: { enabled: true }, - requestId: { - allowFromAnyIp: true, - ipAllowlist: [], - }, - } as any); - registerRouter(router); - - await server.start(); - - expect(supertest(innerServer.listener).get('/a')).rejects.toThrow('socket hang up'); - - await supertest(innerServer.listener).get('/b').expect(200); - }); - - afterAll(async () => { - await server.stop(); - }); -}); - -describe('getServerOptions', () => { - beforeEach(() => - jest.requireMock('fs').readFileSync.mockImplementation((path: string) => `content-${path}`) - ); - - it('properly configures TLS with default options', () => { - const httpConfig = new HttpConfig( - config.schema.validate({ - ssl: { - enabled: true, - key: 'some-key-path', - certificate: 'some-certificate-path', - }, - }), - {} as any, - {} as any - ); - - expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` - Object { - "ca": undefined, - "cert": "content-some-certificate-path", - "ciphers": "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", - "honorCipherOrder": true, - "key": "content-some-key-path", - "passphrase": undefined, - "rejectUnauthorized": false, - "requestCert": false, - "secureOptions": 67108864, - } - `); - }); - - it('properly configures TLS with client authentication', () => { - const httpConfig = new HttpConfig( - config.schema.validate({ - ssl: { - enabled: true, - key: 'some-key-path', - certificate: 'some-certificate-path', - certificateAuthorities: ['ca-1', 'ca-2'], - clientAuthentication: 'required', - }, - }), - {} as any, - {} as any - ); - - expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` - Object { - "ca": Array [ - "content-ca-1", - "content-ca-2", - ], - "cert": "content-some-certificate-path", - "ciphers": "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", - "honorCipherOrder": true, - "key": "content-some-key-path", - "passphrase": undefined, - "rejectUnauthorized": true, - "requestCert": true, - "secureOptions": 67108864, - } - `); - }); - - it('properly configures CORS when cors enabled', () => { - const httpConfig = new HttpConfig( - config.schema.validate({ - cors: { - enabled: true, - allowCredentials: false, - allowOrigin: ['*'], - }, - }), - {} as any, - {} as any - ); - - expect(getServerOptions(httpConfig).routes?.cors).toEqual({ - credentials: false, - origin: ['*'], - headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf'], - }); - }); -}); - -describe('getRequestId', () => { - describe('when allowFromAnyIp is true', () => { - it('generates a UUID if no x-opaque-id header is present', () => { - const request = { - headers: {}, - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( - 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - ); - }); - - it('uses x-opaque-id header value if present', () => { - const request = { - headers: { - 'x-opaque-id': 'id from header', - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( - 'id from header' - ); - }); - }); - - describe('when allowFromAnyIp is false', () => { - describe('and ipAllowlist is empty', () => { - it('generates a UUID even if x-opaque-id header is present', () => { - const request = { - headers: { 'x-opaque-id': 'id from header' }, - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: [] })).toEqual( - 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - ); - }); - }); - - describe('and ipAllowlist is not empty', () => { - it('uses x-opaque-id header if request comes from trusted IP address', () => { - const request = { - headers: { 'x-opaque-id': 'id from header' }, - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( - 'id from header' - ); - }); - - it('generates a UUID if request comes from untrusted IP address', () => { - const request = { - headers: { 'x-opaque-id': 'id from header' }, - raw: { req: { socket: { remoteAddress: '5.5.5.5' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( - 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - ); - }); - - it('generates UUID if request comes from trusted IP address but no x-opaque-id header is present', () => { - const request = { - headers: {}, - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( - 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - ); - }); - }); - }); -}); diff --git a/src/core/server/http/http_tools.ts b/src/core/server/http/http_tools.ts deleted file mode 100644 index e909b454feae2c..00000000000000 --- a/src/core/server/http/http_tools.ts +++ /dev/null @@ -1,186 +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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { Server } from '@hapi/hapi'; -import type { - Lifecycle, - Request, - ResponseToolkit, - RouteOptionsCors, - ServerOptions, - Util, -} from '@hapi/hapi'; -import Hoek from '@hapi/hoek'; -import type { ServerOptions as TLSOptions } from 'https'; -import type { ValidationError } from 'joi'; -import uuid from 'uuid'; -import { ensureNoUnsafeProperties } from '@kbn/std'; -import { HttpConfig } from './http_config'; - -const corsAllowedHeaders = ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf']; -/** - * Converts Kibana `HttpConfig` into `ServerOptions` that are accepted by the Hapi server. - */ -export function getServerOptions(config: HttpConfig, { configureTLS = true } = {}) { - const cors: RouteOptionsCors | false = config.cors.enabled - ? { - credentials: config.cors.allowCredentials, - origin: config.cors.allowOrigin, - headers: corsAllowedHeaders, - } - : false; - // Note that all connection options configured here should be exactly the same - // as in the legacy platform server (see `src/legacy/server/http/index`). Any change - // SHOULD BE applied in both places. The only exception is TLS-specific options, - // that are configured only here. - const options: ServerOptions = { - host: config.host, - port: config.port, - routes: { - cache: { - privacy: 'private', - otherwise: 'private, no-cache, no-store, must-revalidate', - }, - cors, - payload: { - maxBytes: config.maxPayload.getValueInBytes(), - }, - validate: { - failAction: defaultValidationErrorHandler, - options: { - abortEarly: false, - }, - // TODO: This payload validation can be removed once the legacy platform is completely removed. - // This is a default payload validation which applies to all LP routes which do not specify their own - // `validate.payload` handler, in order to reduce the likelyhood of prototype pollution vulnerabilities. - // (All NP routes are already required to specify their own validation in order to access the payload) - payload: (value) => Promise.resolve(ensureNoUnsafeProperties(value)), - }, - }, - state: { - strictHeader: false, - isHttpOnly: true, - isSameSite: false, // necessary to allow using Kibana inside an iframe - }, - }; - - if (configureTLS && config.ssl.enabled) { - const ssl = config.ssl; - - // TODO: Hapi types have a typo in `tls` property type definition: `https.RequestOptions` is used instead of - // `https.ServerOptions`, and `honorCipherOrder` isn't presented in `https.RequestOptions`. - const tlsOptions: TLSOptions = { - ca: ssl.certificateAuthorities, - cert: ssl.certificate, - ciphers: config.ssl.cipherSuites.join(':'), - // We use the server's cipher order rather than the client's to prevent the BEAST attack. - honorCipherOrder: true, - key: ssl.key, - passphrase: ssl.keyPassphrase, - secureOptions: ssl.getSecureOptions(), - requestCert: ssl.requestCert, - rejectUnauthorized: ssl.rejectUnauthorized, - }; - - options.tls = tlsOptions; - } - - return options; -} - -export function getListenerOptions(config: HttpConfig) { - return { - keepaliveTimeout: config.keepaliveTimeout, - socketTimeout: config.socketTimeout, - }; -} - -interface ListenerOptions { - keepaliveTimeout: number; - socketTimeout: number; -} - -export function createServer(serverOptions: ServerOptions, listenerOptions: ListenerOptions) { - const server = new Server(serverOptions); - - server.listener.keepAliveTimeout = listenerOptions.keepaliveTimeout; - server.listener.setTimeout(listenerOptions.socketTimeout); - server.listener.on('timeout', (socket) => { - socket.destroy(); - }); - server.listener.on('clientError', (err, socket) => { - if (socket.writable) { - socket.end(Buffer.from('HTTP/1.1 400 Bad Request\r\n\r\n', 'ascii')); - } else { - socket.destroy(err); - } - }); - - return server; -} - -/** - * Hapi extends the ValidationError interface to add this output key with more data. - */ -export interface HapiValidationError extends ValidationError { - output: { - statusCode: number; - headers: Util.Dictionary; - payload: { - statusCode: number; - error: string; - message?: string; - validation: { - source: string; - keys: string[]; - }; - }; - }; -} - -/** - * Used to replicate Hapi v16 and below's validation responses. Should be used in the routes.validate.failAction key. - */ -export function defaultValidationErrorHandler( - request: Request, - h: ResponseToolkit, - err?: Error -): Lifecycle.ReturnValue { - // Newer versions of Joi don't format the key for missing params the same way. This shim - // provides backwards compatibility. Unfortunately, Joi doesn't export it's own Error class - // in JS so we have to rely on the `name` key before we can cast it. - // - // The Hapi code we're 'overwriting' can be found here: - // https://github.com/hapijs/hapi/blob/master/lib/validation.js#L102 - if (err && err.name === 'ValidationError' && err.hasOwnProperty('output')) { - const validationError: HapiValidationError = err as HapiValidationError; - const validationKeys: string[] = []; - - validationError.details.forEach((detail) => { - if (detail.path.length > 0) { - validationKeys.push(Hoek.escapeHtml(detail.path.join('.'))); - } else { - // If no path, use the value sigil to signal the entire value had an issue. - validationKeys.push('value'); - } - }); - - validationError.output.payload.validation.keys = validationKeys; - } - - throw err; -} - -export function getRequestId(request: Request, options: HttpConfig['requestId']): string { - return options.allowFromAnyIp || - // socket may be undefined in integration tests that connect via the http listener directly - (request.raw.req.socket?.remoteAddress && - options.ipAllowlist.includes(request.raw.req.socket.remoteAddress)) - ? request.headers['x-opaque-id'] ?? uuid.v4() - : uuid.v4(); -} diff --git a/src/core/server/http/https_redirect_server.ts b/src/core/server/http/https_redirect_server.ts index dd29a46d728e72..0eb5cedbc15929 100644 --- a/src/core/server/http/https_redirect_server.ts +++ b/src/core/server/http/https_redirect_server.ts @@ -8,10 +8,10 @@ import { Request, ResponseToolkit, Server } from '@hapi/hapi'; import { format as formatUrl } from 'url'; +import { createServer, getListenerOptions, getServerOptions } from '@kbn/http-tools'; import { Logger } from '../logging'; import { HttpConfig } from './http_config'; -import { createServer, getListenerOptions, getServerOptions } from './http_tools'; export class HttpsRedirectServer { private server?: Server; diff --git a/src/core/server/http/integration_tests/router.test.ts b/src/core/server/http/integration_tests/router.test.ts index 03324dc6c722ff..3406d5dbd473f0 100644 --- a/src/core/server/http/integration_tests/router.test.ts +++ b/src/core/server/http/integration_tests/router.test.ts @@ -9,16 +9,16 @@ import { Stream } from 'stream'; import Boom from '@hapi/boom'; import supertest from 'supertest'; -import { schema } from '@kbn/config-schema'; - -import { HttpService } from '../http_service'; +import { ByteSizeValue, schema } from '@kbn/config-schema'; import { contextServiceMock } from '../../context/context_service.mock'; import { loggingSystemMock } from '../../logging/logging_system.mock'; import { createHttpServer } from '../test_utils'; +import { HttpServer } from '../http_server'; +import { Router } from '../router'; +import { HttpService } from '../http_service'; let server: HttpService; - let logger: ReturnType; const contextSetup = contextServiceMock.createSetupContract(); @@ -28,7 +28,6 @@ const setupDeps = { beforeEach(() => { logger = loggingSystemMock.create(); - server = createHttpServer({ logger }); }); @@ -1839,3 +1838,49 @@ describe('ETag', () => { .expect(304, ''); }); }); + +describe('Timeouts', () => { + let httpServer: HttpServer; + let router: Router; + + beforeEach(() => { + httpServer = new HttpServer(logger, 'foo'); + const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, {}); + router = new Router('', logger.get(), enhanceWithContext); + }); + + afterEach(async () => { + await httpServer.stop(); + }); + + test('closes sockets on timeout', async () => { + router.get({ path: '/a', validate: false }, async (context, req, res) => { + await new Promise((resolve) => setTimeout(resolve, 2000)); + return res.ok({}); + }); + router.get({ path: '/b', validate: false }, (context, req, res) => res.ok({})); + + const { registerRouter, server: innerServer } = await httpServer.setup({ + socketTimeout: 1000, + host: '127.0.0.1', + maxPayload: new ByteSizeValue(1024), + ssl: {}, + cors: { + enabled: false, + }, + compression: { enabled: true }, + requestId: { + allowFromAnyIp: true, + ipAllowlist: [], + }, + } as any); + + registerRouter(router); + + await httpServer.start(); + + expect(supertest(innerServer.listener).get('/a')).rejects.toThrow('socket hang up'); + + await supertest(innerServer.listener).get('/b').expect(200); + }); +}); diff --git a/src/core/server/http/ssl_config.ts b/src/core/server/http/ssl_config.ts index 917d416a775639..13d330fbd6ec51 100644 --- a/src/core/server/http/ssl_config.ts +++ b/src/core/server/http/ssl_config.ts @@ -81,14 +81,13 @@ type SslConfigType = TypeOf; export class SslConfig { public enabled: boolean; - public redirectHttpFromPort: number | undefined; - public key: string | undefined; - public certificate: string | undefined; - public certificateAuthorities: string[] | undefined; - public keyPassphrase: string | undefined; + public redirectHttpFromPort?: number; + public key?: string; + public certificate?: string; + public certificateAuthorities?: string[]; + public keyPassphrase?: string; public requestCert: boolean; public rejectUnauthorized: boolean; - public cipherSuites: string[]; public supportedProtocols: string[]; @@ -146,7 +145,7 @@ export class SslConfig { /** * Options that affect the OpenSSL protocol behavior via numeric bitmask of the SSL_OP_* options from OpenSSL Options. */ - public getSecureOptions() { + public get secureOptions() { // our validation should ensure that this.supportedProtocols is at least an empty array, // which the following logic depends upon. if (this.supportedProtocols == null || this.supportedProtocols.length === 0) { diff --git a/yarn.lock b/yarn.lock index 74bca3901dfe1f..4a82aea6c42363 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2653,6 +2653,10 @@ version "0.0.0" uid "" +"@kbn/http-tools@link:packages/kbn-http-tools": + version "0.0.0" + uid "" + "@kbn/i18n@link:packages/kbn-i18n": version "0.0.0" uid "" From 3c7ca94171bb03e99f702a91b184414442bd6509 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Tue, 23 Mar 2021 11:49:36 +0100 Subject: [PATCH 02/38] fix readme --- packages/kbn-http-tools/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-http-tools/README.md b/packages/kbn-http-tools/README.md index fd132e4312487f..c53b7b85354383 100644 --- a/packages/kbn-http-tools/README.md +++ b/packages/kbn-http-tools/README.md @@ -1,3 +1,3 @@ -# @kbn/utils +# @kbn/http-tools -Shared server-side utilities shared across packages and plugins. \ No newline at end of file +Http utilities for core and the basepath server \ No newline at end of file From a617ef8c9362c4571e177d57260c9185aa347112 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Tue, 23 Mar 2021 16:41:40 +0100 Subject: [PATCH 03/38] start moving stuff --- packages/kbn-config/src/index.ts | 7 +- packages/kbn-config/src/raw/index.ts | 2 +- .../kbn-config/src/raw/raw_config_service.ts | 2 +- src/core/server/http/http_config.ts | 3 +- src/core/server/http/index.ts | 1 - src/core/server/http/ssl_config.ts | 4 +- src/core/server/legacy/legacy_service.ts | 45 ++--------- .../base_path_proxy_server.test.ts | 0 .../cli_dev_mode}/base_path_proxy_server.ts | 40 ++++----- src/dev/cli_dev_mode/bootstrap.ts | 43 ++++++++++ src/dev/cli_dev_mode/cli_dev_mode.ts | 81 ++++++++----------- src/dev/cli_dev_mode/config/dev_config.ts | 28 +++++++ src/dev/cli_dev_mode/config/http_config.ts | 68 ++++++++++++++++ src/dev/cli_dev_mode/config/index.ts | 13 +++ src/dev/cli_dev_mode/config/load_config.ts | 44 ++++++++++ src/dev/cli_dev_mode/config/plugins_config.ts | 37 +++++++++ src/dev/cli_dev_mode/config/types.ts | 17 ++++ src/dev/cli_dev_mode/index.ts | 4 +- src/dev/cli_dev_mode/log_adapter.ts | 35 ++++++++ src/dev/cli_dev_mode/optimizer.ts | 2 + 20 files changed, 361 insertions(+), 115 deletions(-) rename src/{core/server/http => dev/cli_dev_mode}/base_path_proxy_server.test.ts (100%) rename src/{core/server/http => dev/cli_dev_mode}/base_path_proxy_server.ts (91%) create mode 100644 src/dev/cli_dev_mode/bootstrap.ts create mode 100644 src/dev/cli_dev_mode/config/dev_config.ts create mode 100644 src/dev/cli_dev_mode/config/http_config.ts create mode 100644 src/dev/cli_dev_mode/config/index.ts create mode 100644 src/dev/cli_dev_mode/config/load_config.ts create mode 100644 src/dev/cli_dev_mode/config/plugins_config.ts create mode 100644 src/dev/cli_dev_mode/config/types.ts create mode 100644 src/dev/cli_dev_mode/log_adapter.ts diff --git a/packages/kbn-config/src/index.ts b/packages/kbn-config/src/index.ts index 24f271c979f321..8b0bdb0befbfdb 100644 --- a/packages/kbn-config/src/index.ts +++ b/packages/kbn-config/src/index.ts @@ -16,7 +16,12 @@ export { ConfigDeprecationWithContext, } from './deprecation'; -export { RawConfigurationProvider, RawConfigService, getConfigFromFiles } from './raw'; +export { + RawConfigurationProvider, + RawConfigService, + RawConfigAdapter, + getConfigFromFiles, +} from './raw'; export { ConfigService, IConfigService } from './config_service'; export { Config, ConfigPath, isConfigPath, hasConfigPathIntersection } from './config'; diff --git a/packages/kbn-config/src/raw/index.ts b/packages/kbn-config/src/raw/index.ts index 8f65e7877ba56f..01ad83728aa085 100644 --- a/packages/kbn-config/src/raw/index.ts +++ b/packages/kbn-config/src/raw/index.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export { RawConfigService, RawConfigurationProvider } from './raw_config_service'; +export { RawConfigService, RawConfigurationProvider, RawConfigAdapter } from './raw_config_service'; export { getConfigFromFiles } from './read_config'; diff --git a/packages/kbn-config/src/raw/raw_config_service.ts b/packages/kbn-config/src/raw/raw_config_service.ts index af901f2b3d28e3..cce1132bebdb0e 100644 --- a/packages/kbn-config/src/raw/raw_config_service.ts +++ b/packages/kbn-config/src/raw/raw_config_service.ts @@ -13,7 +13,7 @@ import typeDetect from 'type-detect'; import { getConfigFromFiles } from './read_config'; -type RawConfigAdapter = (rawConfig: Record) => Record; +export type RawConfigAdapter = (rawConfig: Record) => Record; export type RawConfigurationProvider = Pick; diff --git a/src/core/server/http/http_config.ts b/src/core/server/http/http_config.ts index 2bbe9f3f96a559..2b8533a78f1c3d 100644 --- a/src/core/server/http/http_config.ts +++ b/src/core/server/http/http_config.ts @@ -7,6 +7,7 @@ */ import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema'; +import { IHttpConfig } from '@kbn/http-tools'; import { hostname } from 'os'; import url from 'url'; @@ -156,7 +157,7 @@ export const config = { }; export type HttpConfigType = TypeOf; -export class HttpConfig { +export class HttpConfig implements IHttpConfig { public name: string; public autoListen: boolean; public host: string; diff --git a/src/core/server/http/index.ts b/src/core/server/http/index.ts index c35b7e2fcd0429..84fe5149c89c66 100644 --- a/src/core/server/http/index.ts +++ b/src/core/server/http/index.ts @@ -56,7 +56,6 @@ export type { DestructiveRouteMethod, SafeRouteMethod, } from './router'; -export { BasePathProxyServer } from './base_path_proxy_server'; export type { OnPreRoutingHandler, OnPreRoutingToolkit } from './lifecycle/on_pre_routing'; export type { AuthenticationHandler, diff --git a/src/core/server/http/ssl_config.ts b/src/core/server/http/ssl_config.ts index 13d330fbd6ec51..a3984e10cd232e 100644 --- a/src/core/server/http/ssl_config.ts +++ b/src/core/server/http/ssl_config.ts @@ -163,6 +163,4 @@ export class SslConfig { } } -const readFile = (file: string) => { - return readFileSync(file, 'utf8'); -}; +const readFile = (file: string) => readFileSync(file, 'utf8'); diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index 63b84e2461e71b..f7abe942d0009d 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { combineLatest, ConnectableObservable, EMPTY, Observable, Subscription } from 'rxjs'; +import { combineLatest, ConnectableObservable, Observable, Subscription } from 'rxjs'; import { first, map, publishReplay, tap } from 'rxjs/operators'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { PathConfigType } from '@kbn/utils'; @@ -18,9 +18,7 @@ import { CoreService } from '../../types'; import { Config } from '../config'; import { CoreContext } from '../core_context'; import { CspConfigType, config as cspConfig } from '../csp'; -import { DevConfig, DevConfigType, config as devConfig } from '../dev'; import { - BasePathProxyServer, HttpConfig, HttpConfigType, config as httpConfig, @@ -64,7 +62,6 @@ export class LegacyService implements CoreService { /** Symbol to represent the legacy platform as a fake "plugin". Used by the ContextService */ public readonly legacyId = Symbol(); private readonly log: Logger; - private readonly devConfig$: Observable; private readonly httpConfig$: Observable; private kbnServer?: LegacyKbnServer; private configSubscription?: Subscription; @@ -77,9 +74,6 @@ export class LegacyService implements CoreService { const { logger, configService } = coreContext; this.log = logger.get('legacy-service'); - this.devConfig$ = configService - .atPath(devConfig.path) - .pipe(map((rawConfig) => new DevConfig(rawConfig))); this.httpConfig$ = combineLatest( configService.atPath(httpConfig.path), configService.atPath(cspConfig.path), @@ -142,17 +136,12 @@ export class LegacyService implements CoreService { this.log.debug('starting legacy service'); - // Receive initial config and create kbnServer/ClusterManager. - if (this.coreContext.env.isDevCliParent) { - await this.setupCliDevMode(this.legacyRawConfig!); - } else { - this.kbnServer = await this.createKbnServer( - this.settings!, - this.legacyRawConfig!, - setupDeps, - startDeps - ); - } + this.kbnServer = await this.createKbnServer( + this.settings!, + this.legacyRawConfig!, + setupDeps, + startDeps + ); } public async stop() { @@ -169,26 +158,6 @@ export class LegacyService implements CoreService { } } - private async setupCliDevMode(config: LegacyConfig) { - const basePathProxy$ = this.coreContext.env.cliArgs.basePath - ? combineLatest([this.devConfig$, this.httpConfig$]).pipe( - first(), - map( - ([dev, http]) => - new BasePathProxyServer(this.coreContext.logger.get('server'), http, dev) - ) - ) - : EMPTY; - - // eslint-disable-next-line @typescript-eslint/no-var-requires - const { CliDevMode } = require('./cli_dev_mode'); - CliDevMode.fromCoreServices( - this.coreContext.env.cliArgs, - config, - await basePathProxy$.toPromise() - ); - } - private async createKbnServer( settings: LegacyVars, config: LegacyConfig, diff --git a/src/core/server/http/base_path_proxy_server.test.ts b/src/dev/cli_dev_mode/base_path_proxy_server.test.ts similarity index 100% rename from src/core/server/http/base_path_proxy_server.test.ts rename to src/dev/cli_dev_mode/base_path_proxy_server.test.ts diff --git a/src/core/server/http/base_path_proxy_server.ts b/src/dev/cli_dev_mode/base_path_proxy_server.ts similarity index 91% rename from src/core/server/http/base_path_proxy_server.ts rename to src/dev/cli_dev_mode/base_path_proxy_server.ts index 7db6c93c8ec238..d8abf915008420 100644 --- a/src/core/server/http/base_path_proxy_server.ts +++ b/src/dev/cli_dev_mode/base_path_proxy_server.ts @@ -8,7 +8,6 @@ import Url from 'url'; import { Agent as HttpsAgent, ServerOptions as TlsOptions } from 'https'; - import apm from 'elastic-apm-node'; import { Server, Request } from '@hapi/hapi'; import HapiProxy from '@hapi/h2o2'; @@ -18,11 +17,12 @@ import { take } from 'rxjs/operators'; import { ByteSizeValue } from '@kbn/config-schema'; import { createServer, getListenerOptions, getServerOptions } from '@kbn/http-tools'; -import { DevConfig } from '../dev'; -import { Logger } from '../logging'; -import { HttpConfig } from './http_config'; +import { DevConfig, HttpConfig } from './config'; +import { Log } from './log'; +const ONE_GIGABYTE = 1024 * 1024 * 1024; const alphabet = 'abcdefghijklmnopqrztuvwxyz'.split(''); +const getRandomBasePath = () => sampleSize(alphabet, 3).join(''); export interface BasePathProxyServerOptions { shouldRedirectFromOldBasePath: (path: string) => boolean; @@ -30,9 +30,22 @@ export interface BasePathProxyServerOptions { } export class BasePathProxyServer { + private readonly httpConfig: HttpConfig; private server?: Server; private httpsAgent?: HttpsAgent; + constructor( + private readonly log: Log, + httpConfig: HttpConfig, + private readonly devConfig: DevConfig + ) { + this.httpConfig = { + ...httpConfig, + maxPayload: new ByteSizeValue(ONE_GIGABYTE), + basePath: httpConfig.basePath ?? `/${getRandomBasePath()}`, + }; + } + public get basePath() { return this.httpConfig.basePath; } @@ -49,21 +62,8 @@ export class BasePathProxyServer { return this.httpConfig.port; } - constructor( - private readonly log: Logger, - private readonly httpConfig: HttpConfig, - private readonly devConfig: DevConfig - ) { - const ONE_GIGABYTE = 1024 * 1024 * 1024; - httpConfig.maxPayload = new ByteSizeValue(ONE_GIGABYTE); - - if (!httpConfig.basePath) { - httpConfig.basePath = `/${sampleSize(alphabet, 3).join('')}`; - } - } - public async start(options: Readonly) { - this.log.debug('starting basepath proxy server'); + this.log.good('starting basepath proxy server'); const serverOptions = getServerOptions(this.httpConfig); const listenerOptions = getListenerOptions(this.httpConfig); @@ -88,7 +88,7 @@ export class BasePathProxyServer { await this.server.start(); - this.log.info( + this.log.good( `basepath proxy server running at ${Url.format({ host: this.server.info.uri, pathname: this.httpConfig.basePath, @@ -101,7 +101,7 @@ export class BasePathProxyServer { return; } - this.log.debug('stopping basepath proxy server'); + this.log.good('stopping basepath proxy server'); await this.server.stop(); this.server = undefined; diff --git a/src/dev/cli_dev_mode/bootstrap.ts b/src/dev/cli_dev_mode/bootstrap.ts new file mode 100644 index 00000000000000..b8f1a4161d0cd7 --- /dev/null +++ b/src/dev/cli_dev_mode/bootstrap.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { REPO_ROOT } from '@kbn/utils'; +import { CliArgs, Env } from '@kbn/config'; +import { CliDevMode } from './cli_dev_mode'; +import { CliLog } from './log'; +import { convertToLogger } from './log_adapter'; +import { loadConfig } from './config'; + +interface BootstrapArgs { + configs: string[]; + cliArgs: CliArgs; +} + +export async function bootstrapDevMode({ configs, cliArgs }: BootstrapArgs) { + const log = new CliLog(!!cliArgs.quiet, !!cliArgs.silent); + + const env = Env.createDefault(REPO_ROOT, { + configs, + cliArgs, + isDevCliParent: true, + }); + + const config = await loadConfig({ + env, + logger: convertToLogger(log), + rawConfigAdapter: (cfg) => cfg, // TODO: use from cli/serve + }); + + const cliDevMode = new CliDevMode({ + cliArgs, + config, + log, + }); + + await cliDevMode.start(); +} diff --git a/src/dev/cli_dev_mode/cli_dev_mode.ts b/src/dev/cli_dev_mode/cli_dev_mode.ts index 1eed8b14aed4ab..5337a463b3cd80 100644 --- a/src/dev/cli_dev_mode/cli_dev_mode.ts +++ b/src/dev/cli_dev_mode/cli_dev_mode.ts @@ -11,24 +11,31 @@ import Path from 'path'; import { REPO_ROOT, CiStatsReporter } from '@kbn/dev-utils'; import * as Rx from 'rxjs'; import { map, mapTo, filter, take, tap, distinctUntilChanged, switchMap } from 'rxjs/operators'; - -import { CliArgs } from '../../core/server/config'; -import { LegacyConfig } from '../../core/server/legacy'; -import { BasePathProxyServer } from '../../core/server/http'; +import { CliArgs } from '@kbn/config'; import { Log, CliLog } from './log'; import { Optimizer } from './optimizer'; import { DevServer } from './dev_server'; import { Watcher } from './watcher'; +import { BasePathProxyServer } from './base_path_proxy_server'; import { shouldRedirectFromOldBasePath } from './should_redirect_from_old_base_path'; import { getServerWatchPaths } from './get_server_watch_paths'; +import { CliDevConfig } from './config'; // timeout where the server is allowed to exit gracefully const GRACEFUL_TIMEOUT = 5000; export type SomeCliArgs = Pick< CliArgs, - 'quiet' | 'silent' | 'disableOptimizer' | 'watch' | 'oss' | 'runExamples' | 'cache' | 'dist' + | 'quiet' + | 'silent' + | 'disableOptimizer' + | 'watch' + | 'oss' + | 'runExamples' + | 'cache' + | 'dist' + | 'basePath' >; export interface CliDevModeOptions { @@ -67,49 +74,28 @@ const firstAllTrue = (...sources: Array>) => * */ export class CliDevMode { - static fromCoreServices( - cliArgs: SomeCliArgs, - config: LegacyConfig, - basePathProxy?: BasePathProxyServer - ) { - new CliDevMode({ - quiet: !!cliArgs.quiet, - silent: !!cliArgs.silent, - cache: !!cliArgs.cache, - disableOptimizer: !!cliArgs.disableOptimizer, - dist: !!cliArgs.dist, - oss: !!cliArgs.oss, - runExamples: !!cliArgs.runExamples, - pluginPaths: config.get('plugins.paths'), - pluginScanDirs: config.get('plugins.scanDirs'), - watch: !!cliArgs.watch, - basePathProxy, - }).start(); - } private readonly log: Log; private readonly basePathProxy?: BasePathProxyServer; private readonly watcher: Watcher; private readonly devServer: DevServer; private readonly optimizer: Optimizer; private startTime?: number; - private subscription?: Rx.Subscription; - constructor(options: CliDevModeOptions) { - this.basePathProxy = options.basePathProxy; - this.log = options.log || new CliLog(!!options.quiet, !!options.silent); + constructor({ cliArgs, config, log }: { cliArgs: SomeCliArgs; config: CliDevConfig; log?: Log }) { + this.log = log || new CliLog(!!cliArgs.quiet, !!cliArgs.silent); + + if (cliArgs.basePath) { + this.basePathProxy = new BasePathProxyServer(this.log, config.http, config.dev); + } const { watchPaths, ignorePaths } = getServerWatchPaths({ - pluginPaths: options.pluginPaths ?? [], - pluginScanDirs: [ - ...(options.pluginScanDirs ?? []), - Path.resolve(REPO_ROOT, 'src/plugins'), - Path.resolve(REPO_ROOT, 'x-pack/plugins'), - ], + pluginPaths: config.plugins.additionalPluginPaths, + pluginScanDirs: config.plugins.pluginSearchPaths, }); this.watcher = new Watcher({ - enabled: !!options.watch, + enabled: !!cliArgs.watch, log: this.log, cwd: REPO_ROOT, paths: watchPaths, @@ -124,10 +110,10 @@ export class CliDevMode { script: Path.resolve(REPO_ROOT, 'scripts/kibana'), argv: [ ...process.argv.slice(2).filter((v) => v !== '--no-watch'), - ...(options.basePathProxy + ...(this.basePathProxy ? [ - `--server.port=${options.basePathProxy.targetPort}`, - `--server.basePath=${options.basePathProxy.basePath}`, + `--server.port=${this.basePathProxy.targetPort}`, + `--server.basePath=${this.basePathProxy.basePath}`, '--server.rewriteBasePath=true', ] : []), @@ -144,16 +130,17 @@ export class CliDevMode { }); this.optimizer = new Optimizer({ - enabled: !options.disableOptimizer, + enabled: !cliArgs.disableOptimizer, repoRoot: REPO_ROOT, - oss: options.oss, - pluginPaths: options.pluginPaths, - runExamples: options.runExamples, - cache: options.cache, - dist: options.dist, - quiet: options.quiet, - silent: options.silent, - watch: options.watch, + oss: cliArgs.oss, + pluginPaths: config.plugins.additionalPluginPaths, + pluginScanDirs: config.plugins.pluginSearchPaths, + runExamples: cliArgs.runExamples, + cache: cliArgs.cache, + dist: cliArgs.dist, + quiet: !!cliArgs.quiet, + silent: !!cliArgs.silent, + watch: cliArgs.watch, }); } diff --git a/src/dev/cli_dev_mode/config/dev_config.ts b/src/dev/cli_dev_mode/config/dev_config.ts new file mode 100644 index 00000000000000..ddb54bb8f3f7c9 --- /dev/null +++ b/src/dev/cli_dev_mode/config/dev_config.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +export const devConfigSchema = schema.object( + { + basePathProxyTarget: schema.number({ + defaultValue: 5603, + }), + }, + { unknowns: 'ignore' } +); + +export type DevConfigType = TypeOf; + +export class DevConfig { + public basePathProxyTargetPort: number; + + constructor(rawConfig: DevConfigType) { + this.basePathProxyTargetPort = rawConfig.basePathProxyTarget; + } +} diff --git a/src/dev/cli_dev_mode/config/http_config.ts b/src/dev/cli_dev_mode/config/http_config.ts new file mode 100644 index 00000000000000..1a0b9586dff086 --- /dev/null +++ b/src/dev/cli_dev_mode/config/http_config.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema'; +import { ICorsConfig, IHttpConfig, ISslConfig } from '@kbn/http-tools'; + +export const httpConfigSchema = schema.object( + { + host: schema.string({ + defaultValue: 'localhost', + hostname: true, + }), + basePath: schema.maybe(schema.string()), + port: schema.number({ + defaultValue: 5601, + }), + maxPayload: schema.byteSize({ + defaultValue: '1048576b', + }), + keepaliveTimeout: schema.number({ + defaultValue: 120000, + }), + socketTimeout: schema.number({ + defaultValue: 120000, + }), + cors: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + allowCredentials: schema.boolean({ defaultValue: false }), + allowOrigin: schema.arrayOf(schema.string(), { + defaultValue: ['*'], + }), + }), + // TODO: SSL + }, + { unknowns: 'ignore' } +); + +export type HttpConfigType = TypeOf; + +export class HttpConfig implements IHttpConfig { + basePath?: string; + host: string; + port: number; + maxPayload: ByteSizeValue; + keepaliveTimeout: number; + socketTimeout: number; + cors: ICorsConfig; + ssl: ISslConfig; + + constructor(rawConfig: HttpConfigType) { + this.basePath = rawConfig.basePath; + this.host = rawConfig.host; + this.port = rawConfig.port; + this.maxPayload = rawConfig.maxPayload; + this.keepaliveTimeout = rawConfig.keepaliveTimeout; + this.socketTimeout = rawConfig.socketTimeout; + this.cors = rawConfig.cors; + // TODO: SSL + this.ssl = { + enabled: false, + }; + } +} diff --git a/src/dev/cli_dev_mode/config/index.ts b/src/dev/cli_dev_mode/config/index.ts new file mode 100644 index 00000000000000..89f6d647ef4f51 --- /dev/null +++ b/src/dev/cli_dev_mode/config/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { DevConfig } from './dev_config'; +export type { PluginsConfig } from './plugins_config'; +export type { HttpConfig } from './http_config'; +export type { CliDevConfig } from './types'; +export { loadConfig } from './load_config'; diff --git a/src/dev/cli_dev_mode/config/load_config.ts b/src/dev/cli_dev_mode/config/load_config.ts new file mode 100644 index 00000000000000..46129834ca2d9e --- /dev/null +++ b/src/dev/cli_dev_mode/config/load_config.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Env, RawConfigService, ConfigService, RawConfigAdapter } from '@kbn/config'; +import { Logger } from '@kbn/logging'; +import { devConfigSchema, DevConfig, DevConfigType } from './dev_config'; +import { httpConfigSchema, HttpConfig, HttpConfigType } from './http_config'; +import { pluginsConfigSchema, PluginsConfig, PluginsConfigType } from './plugins_config'; +import { CliDevConfig } from './types'; + +export const loadConfig = async ({ + env, + logger, + rawConfigAdapter, +}: { + env: Env; + logger: Logger; + rawConfigAdapter: RawConfigAdapter; +}): Promise => { + const rawConfigService = new RawConfigService(env.configs, rawConfigAdapter); + rawConfigService.loadConfig(); + + const configService = new ConfigService(rawConfigService, env, logger); + configService.setSchema('dev', devConfigSchema); + configService.setSchema('plugins', pluginsConfigSchema); + configService.setSchema('http', httpConfigSchema); + + await configService.validate(); + + const devConfig = configService.atPathSync('dev'); + const pluginsConfig = configService.atPathSync('plugins'); + const httpConfig = configService.atPathSync('http'); + + return { + dev: new DevConfig(devConfig), + plugins: new PluginsConfig(pluginsConfig, env), + http: new HttpConfig(httpConfig), + }; +}; diff --git a/src/dev/cli_dev_mode/config/plugins_config.ts b/src/dev/cli_dev_mode/config/plugins_config.ts new file mode 100644 index 00000000000000..7c7fa8902edb3b --- /dev/null +++ b/src/dev/cli_dev_mode/config/plugins_config.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import { Env } from '@kbn/config'; + +export const pluginsConfigSchema = schema.object( + { + paths: schema.arrayOf(schema.string(), { defaultValue: [] }), + }, + { unknowns: 'ignore' } +); + +export type PluginsConfigType = TypeOf; + +/** @internal */ +export class PluginsConfig { + /** + * Defines directories that we should scan for the plugin subdirectories. + */ + public readonly pluginSearchPaths: string[]; + + /** + * Defines directories where an additional plugin exists. + */ + public readonly additionalPluginPaths: string[]; + + constructor(rawConfig: PluginsConfigType, env: Env) { + this.pluginSearchPaths = [...env.pluginSearchPaths]; + this.additionalPluginPaths = rawConfig.paths; + } +} diff --git a/src/dev/cli_dev_mode/config/types.ts b/src/dev/cli_dev_mode/config/types.ts new file mode 100644 index 00000000000000..017442e09bd0df --- /dev/null +++ b/src/dev/cli_dev_mode/config/types.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { DevConfig } from './dev_config'; +import type { HttpConfig } from './http_config'; +import type { PluginsConfig } from './plugins_config'; + +export interface CliDevConfig { + dev: DevConfig; + http: HttpConfig; + plugins: PluginsConfig; +} diff --git a/src/dev/cli_dev_mode/index.ts b/src/dev/cli_dev_mode/index.ts index db46957504b112..561cc8acf07ae7 100644 --- a/src/dev/cli_dev_mode/index.ts +++ b/src/dev/cli_dev_mode/index.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export * from './cli_dev_mode'; -export * from './log'; +export { CliDevMode, CliDevModeOptions, SomeCliArgs } from './cli_dev_mode'; +export { Log, CliLog, TestLog } from './log'; diff --git a/src/dev/cli_dev_mode/log_adapter.ts b/src/dev/cli_dev_mode/log_adapter.ts new file mode 100644 index 00000000000000..c334afcb32464d --- /dev/null +++ b/src/dev/cli_dev_mode/log_adapter.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { LoggerFactory, Logger } from '@kbn/logging'; +import { Log } from './log'; + +export const convertToLoggerFactory = (cliLog: Log): LoggerFactory => { + const adapted = convertToLogger(cliLog); + return { + get: () => adapted, + }; +}; + +export const convertToLogger = (cliLog: Log): Logger => { + const getErrorMessage = (msgOrError: string | Error): string => { + return typeof msgOrError === 'string' ? msgOrError : msgOrError.message; + }; + + const adapter: Logger = { + trace: (message) => cliLog.good(message), + debug: (message) => cliLog.good(message), + info: (message) => cliLog.good(message), + warn: (msgOrError) => cliLog.warn(getErrorMessage(msgOrError)), + error: (msgOrError) => cliLog.bad(getErrorMessage(msgOrError)), + fatal: (msgOrError) => cliLog.bad(getErrorMessage(msgOrError)), + log: (record) => cliLog.good(record.message), + get: () => adapter, + }; + return adapter; +}; diff --git a/src/dev/cli_dev_mode/optimizer.ts b/src/dev/cli_dev_mode/optimizer.ts index 771da21e6151b8..5e2f16fcf7daa8 100644 --- a/src/dev/cli_dev_mode/optimizer.ts +++ b/src/dev/cli_dev_mode/optimizer.ts @@ -31,6 +31,7 @@ export interface Options { oss: boolean; runExamples: boolean; pluginPaths: string[]; + pluginScanDirs: string[]; writeLogTo?: Writable; } @@ -56,6 +57,7 @@ export class Optimizer { oss: options.oss, examples: options.runExamples, pluginPaths: options.pluginPaths, + pluginScanDirs: options.pluginScanDirs, }); const dim = Chalk.dim('np bld'); From 10dcd75aa041b836c2eeba2125e150aa0d1beb1a Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Tue, 23 Mar 2021 19:44:05 +0100 Subject: [PATCH 04/38] cleaning up `isDevCliParent` --- packages/kbn-config/src/__mocks__/env.ts | 1 - .../src/__snapshots__/env.test.ts.snap | 6 -- packages/kbn-config/src/env.test.ts | 1 - packages/kbn-config/src/env.ts | 8 -- src/cli/serve/serve.js | 3 - src/core/server/bootstrap.ts | 17 +---- src/core/server/http/http_service.test.ts | 23 ------ src/core/server/http/http_service.ts | 2 +- src/core/server/legacy/cli_dev_mode.js | 9 --- src/core/server/legacy/legacy_service.test.ts | 73 ------------------- .../server/plugins/plugins_service.test.ts | 34 +-------- src/core/server/plugins/plugins_service.ts | 17 ++--- src/core/server/root/index.ts | 8 +- src/core/server/server.test.ts | 16 ---- src/core/server/server.ts | 11 +-- src/core/test_helpers/kbn_server.ts | 1 - src/dev/cli_dev_mode/bootstrap.ts | 1 - 17 files changed, 17 insertions(+), 214 deletions(-) delete mode 100644 src/core/server/legacy/cli_dev_mode.js diff --git a/packages/kbn-config/src/__mocks__/env.ts b/packages/kbn-config/src/__mocks__/env.ts index e3b3106933f1e9..6f05f8f1f5a45a 100644 --- a/packages/kbn-config/src/__mocks__/env.ts +++ b/packages/kbn-config/src/__mocks__/env.ts @@ -30,6 +30,5 @@ export function getEnvOptions(options: DeepPartial = {}): EnvOptions runExamples: false, ...(options.cliArgs || {}), }, - isDevCliParent: options.isDevCliParent !== undefined ? options.isDevCliParent : false, }; } diff --git a/packages/kbn-config/src/__snapshots__/env.test.ts.snap b/packages/kbn-config/src/__snapshots__/env.test.ts.snap index fae14529a4af3d..570ed948774cc1 100644 --- a/packages/kbn-config/src/__snapshots__/env.test.ts.snap +++ b/packages/kbn-config/src/__snapshots__/env.test.ts.snap @@ -21,7 +21,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": false, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": true, @@ -65,7 +64,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": false, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": false, @@ -108,7 +106,6 @@ Env { "/test/cwd/config/kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": true, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": true, @@ -151,7 +148,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": false, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": false, @@ -194,7 +190,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": false, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": false, @@ -237,7 +232,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/some/home/dir", - "isDevCliParent": false, "logDir": "/some/home/dir/log", "mode": Object { "dev": false, diff --git a/packages/kbn-config/src/env.test.ts b/packages/kbn-config/src/env.test.ts index 09d44f31cf8d55..b9e97514c2dffb 100644 --- a/packages/kbn-config/src/env.test.ts +++ b/packages/kbn-config/src/env.test.ts @@ -36,7 +36,6 @@ test('correctly creates default environment in dev mode.', () => { REPO_ROOT, getEnvOptions({ configs: ['/test/cwd/config/kibana.yml'], - isDevCliParent: true, }) ); diff --git a/packages/kbn-config/src/env.ts b/packages/kbn-config/src/env.ts index b6ff5e3b5aab22..c4845ab429c573 100644 --- a/packages/kbn-config/src/env.ts +++ b/packages/kbn-config/src/env.ts @@ -15,7 +15,6 @@ import { PackageInfo, EnvironmentMode } from './types'; export interface EnvOptions { configs: string[]; cliArgs: CliArgs; - isDevCliParent: boolean; } /** @internal */ @@ -89,12 +88,6 @@ export class Env { */ public readonly configs: readonly string[]; - /** - * Indicates that this Kibana instance is running in the parent process of the dev cli. - * @internal - */ - public readonly isDevCliParent: boolean; - /** * @internal */ @@ -111,7 +104,6 @@ export class Env { this.cliArgs = Object.freeze(options.cliArgs); this.configs = Object.freeze(options.configs); - this.isDevCliParent = options.isDevCliParent; const isDevMode = this.cliArgs.dev || this.cliArgs.envName === 'development'; this.mode = Object.freeze({ diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 13c16691bf12a2..32aa45f686fca4 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -231,9 +231,6 @@ export default function (program) { cache: !!opts.cache, dist: !!opts.dist, }, - features: { - isCliDevModeSupported: DEV_MODE_SUPPORTED, - }, applyConfigOverrides: (rawConfig) => applyConfigOverrides(rawConfig, opts, unknownOptions), }); }); diff --git a/src/core/server/bootstrap.ts b/src/core/server/bootstrap.ts index 42f6d9aedf1d69..e62671e6c5ec39 100644 --- a/src/core/server/bootstrap.ts +++ b/src/core/server/bootstrap.ts @@ -11,18 +11,10 @@ import { CliArgs, Env, RawConfigService } from './config'; import { Root } from './root'; import { CriticalError } from './errors'; -interface KibanaFeatures { - // Indicates whether we can run Kibana in dev mode in which Kibana is run as - // a child process together with optimizer "worker" processes that are - // orchestrated by a parent process (dev mode only feature). - isCliDevModeSupported: boolean; -} - interface BootstrapArgs { configs: string[]; cliArgs: CliArgs; applyConfigOverrides: (config: Record) => Record; - features: KibanaFeatures; } /** @@ -30,13 +22,9 @@ interface BootstrapArgs { * @internal * @param param0 - options */ -export async function bootstrap({ - configs, - cliArgs, - applyConfigOverrides, - features, -}: BootstrapArgs) { +export async function bootstrap({ configs, cliArgs, applyConfigOverrides }: BootstrapArgs) { if (cliArgs.optimize) { + // TODO: move to devCliMode // --optimize is deprecated and does nothing now, avoid starting up and just shutdown return; } @@ -52,7 +40,6 @@ export async function bootstrap({ const env = Env.createDefault(REPO_ROOT, { configs, cliArgs, - isDevCliParent: cliArgs.dev && features.isCliDevModeSupported && !process.env.isDevCliChild, }); const rawConfigService = new RawConfigService(env.configs, applyConfigOverrides); diff --git a/src/core/server/http/http_service.test.ts b/src/core/server/http/http_service.test.ts index 9354c89b632929..83279e99bc4761 100644 --- a/src/core/server/http/http_service.test.ts +++ b/src/core/server/http/http_service.test.ts @@ -242,29 +242,6 @@ test('returns http server contract on setup', async () => { }); }); -test('does not start http server if process is dev cluster master', async () => { - const configService = createConfigService(); - const httpServer = { - isListening: () => false, - setup: jest.fn().mockReturnValue({}), - start: jest.fn(), - stop: noop, - }; - mockHttpServer.mockImplementation(() => httpServer); - - const service = new HttpService({ - coreId, - configService, - env: Env.createDefault(REPO_ROOT, getEnvOptions({ isDevCliParent: true })), - logger, - }); - - await service.setup(setupDeps); - await service.start(); - - expect(httpServer.start).not.toHaveBeenCalled(); -}); - test('does not start http server if configured with `autoListen:false`', async () => { const configService = createConfigService({ autoListen: false, diff --git a/src/core/server/http/http_service.ts b/src/core/server/http/http_service.ts index 87143e1160c6c3..42f222b6201ff2 100644 --- a/src/core/server/http/http_service.ts +++ b/src/core/server/http/http_service.ts @@ -161,7 +161,7 @@ export class HttpService * @internal * */ private shouldListen(config: HttpConfig) { - return !this.coreContext.env.isDevCliParent && config.autoListen; + return config.autoListen; } public async stop() { diff --git a/src/core/server/legacy/cli_dev_mode.js b/src/core/server/legacy/cli_dev_mode.js deleted file mode 100644 index 3c4bdb4149780a..00000000000000 --- a/src/core/server/legacy/cli_dev_mode.js +++ /dev/null @@ -1,9 +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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -export { CliDevMode } from '../../../dev/cli_dev_mode'; diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts index da6b521bfde9a7..db36bd73602c47 100644 --- a/src/core/server/legacy/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -7,16 +7,12 @@ */ jest.mock('../../../legacy/server/kbn_server'); -jest.mock('./cli_dev_mode'); import { BehaviorSubject, throwError } from 'rxjs'; import { REPO_ROOT } from '@kbn/dev-utils'; -// @ts-expect-error js file to remove TS dependency on cli -import { CliDevMode as MockCliDevMode } from './cli_dev_mode'; import KbnServer from '../../../legacy/server/kbn_server'; import { Config, Env, ObjectToConfigAdapter } from '../config'; -import { BasePathProxyServer } from '../http'; import { DiscoveredPlugin } from '../plugins'; import { getEnvOptions, configServiceMock } from '../config/mocks'; @@ -228,7 +224,6 @@ describe('once LegacyService is set up with connection info', () => { ); expect(MockKbnServer).not.toHaveBeenCalled(); - expect(MockCliDevMode).not.toHaveBeenCalled(); }); test('reconfigures logging configuration if new config is received.', async () => { @@ -335,74 +330,6 @@ describe('once LegacyService is set up without connection info', () => { }); }); -describe('once LegacyService is set up in `devClusterMaster` mode', () => { - beforeEach(() => { - configService.atPath.mockImplementation((path) => { - return new BehaviorSubject( - path === 'dev' ? { basePathProxyTargetPort: 100500 } : { basePath: '/abc' } - ); - }); - }); - - test('creates CliDevMode without base path proxy.', async () => { - const devClusterLegacyService = new LegacyService({ - coreId, - env: Env.createDefault( - REPO_ROOT, - getEnvOptions({ - cliArgs: { silent: true, basePath: false }, - isDevCliParent: true, - }) - ), - logger, - configService: configService as any, - }); - - await devClusterLegacyService.setupLegacyConfig(); - await devClusterLegacyService.setup(setupDeps); - await devClusterLegacyService.start(startDeps); - - expect(MockCliDevMode.fromCoreServices).toHaveBeenCalledTimes(1); - expect(MockCliDevMode.fromCoreServices).toHaveBeenCalledWith( - expect.objectContaining({ silent: true, basePath: false }), - expect.objectContaining({ - get: expect.any(Function), - set: expect.any(Function), - }), - undefined - ); - }); - - test('creates CliDevMode with base path proxy.', async () => { - const devClusterLegacyService = new LegacyService({ - coreId, - env: Env.createDefault( - REPO_ROOT, - getEnvOptions({ - cliArgs: { quiet: true, basePath: true }, - isDevCliParent: true, - }) - ), - logger, - configService: configService as any, - }); - - await devClusterLegacyService.setupLegacyConfig(); - await devClusterLegacyService.setup(setupDeps); - await devClusterLegacyService.start(startDeps); - - expect(MockCliDevMode.fromCoreServices).toHaveBeenCalledTimes(1); - expect(MockCliDevMode.fromCoreServices).toHaveBeenCalledWith( - expect.objectContaining({ quiet: true, basePath: true }), - expect.objectContaining({ - get: expect.any(Function), - set: expect.any(Function), - }), - expect.any(BasePathProxyServer) - ); - }); -}); - describe('start', () => { test('Cannot start without setup phase', async () => { const legacyService = new LegacyService({ diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index 6a49dd963b4e8f..2d54648d229502 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -91,7 +91,7 @@ const createPlugin = ( }); }; -async function testSetup(options: { isDevCliParent?: boolean } = {}) { +async function testSetup() { mockPackage.raw = { branch: 'feature-v1', version: 'v1', @@ -103,10 +103,7 @@ async function testSetup(options: { isDevCliParent?: boolean } = {}) { }; coreId = Symbol('core'); - env = Env.createDefault(REPO_ROOT, { - ...getEnvOptions(), - isDevCliParent: options.isDevCliParent ?? false, - }); + env = Env.createDefault(REPO_ROOT, getEnvOptions()); config$ = new BehaviorSubject>({ plugins: { initialize: true } }); const rawConfigService = rawConfigServiceMock.create({ rawConfig$: config$ }); @@ -626,30 +623,3 @@ describe('PluginsService', () => { }); }); }); - -describe('PluginService when isDevCliParent is true', () => { - beforeEach(async () => { - await testSetup({ - isDevCliParent: true, - }); - }); - - describe('#discover()', () => { - it('does not try to run discovery', async () => { - await expect(pluginsService.discover({ environment: environmentSetup })).resolves - .toMatchInlineSnapshot(` - Object { - "pluginPaths": Array [], - "pluginTree": undefined, - "uiPlugins": Object { - "browserConfigs": Map {}, - "internal": Map {}, - "public": Map {}, - }, - } - `); - - expect(mockDiscover).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index 92b06d7b6a09b7..92ebd2b957bfa0 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -7,7 +7,7 @@ */ import Path from 'path'; -import { Observable, EMPTY } from 'rxjs'; +import { Observable } from 'rxjs'; import { filter, first, map, mergeMap, tap, toArray } from 'rxjs/operators'; import { pick } from '@kbn/std'; @@ -75,11 +75,9 @@ export class PluginsService implements CoreService; private readonly pluginConfigDescriptors = new Map(); private readonly uiPluginInternalInfo = new Map(); - private readonly discoveryDisabled: boolean; constructor(private readonly coreContext: CoreContext) { this.log = coreContext.logger.get('plugins-service'); - this.discoveryDisabled = coreContext.env.isDevCliParent; this.pluginsSystem = new PluginsSystem(coreContext); this.configService = coreContext.configService; this.config$ = coreContext.configService @@ -90,14 +88,9 @@ export class PluginsService implements CoreService(); - const initialize = config.initialize && !this.coreContext.env.isDevCliParent; + const initialize = config.initialize; if (initialize) { contracts = await this.pluginsSystem.setupPlugins(deps); this.registerPluginStaticDirs(deps); diff --git a/src/core/server/root/index.ts b/src/core/server/root/index.ts index f5c684644bc357..b1750483308e98 100644 --- a/src/core/server/root/index.ts +++ b/src/core/server/root/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ConnectableObservable, Subscription, of } from 'rxjs'; +import { ConnectableObservable, Subscription } from 'rxjs'; import { first, publishReplay, switchMap, concatMap, tap } from 'rxjs/operators'; import { Env, RawConfigurationProvider } from '../config'; @@ -25,7 +25,7 @@ export class Root { constructor( rawConfigProvider: RawConfigurationProvider, - private readonly env: Env, + env: Env, private readonly onShutdown?: (reason?: Error | string) => void ) { this.loggingSystem = new LoggingSystem(); @@ -88,9 +88,7 @@ export class Root { const update$ = configService.getConfig$().pipe( // always read the logging config when the underlying config object is re-read // except for the CLI process where we only apply the default logging config once - switchMap(() => - this.env.isDevCliParent ? of(undefined) : configService.atPath('logging') - ), + switchMap(() => configService.atPath('logging')), concatMap((config) => this.loggingSystem.upgrade(config)), // This specifically console.logs because we were not able to configure the logger. // eslint-disable-next-line no-console diff --git a/src/core/server/server.test.ts b/src/core/server/server.test.ts index f2a2b10fdbfde5..fcf09b0295bcbd 100644 --- a/src/core/server/server.test.ts +++ b/src/core/server/server.test.ts @@ -205,19 +205,3 @@ test(`doesn't setup core services if legacy config validation fails`, async () = expect(mockLoggingService.setup).not.toHaveBeenCalled(); expect(mockI18nService.setup).not.toHaveBeenCalled(); }); - -test(`doesn't validate config if env.isDevCliParent is true`, async () => { - const devParentEnv = Env.createDefault(REPO_ROOT, { - ...getEnvOptions(), - isDevCliParent: true, - }); - - const server = new Server(rawConfigService, devParentEnv, logger); - await server.setup(); - - expect(mockEnsureValidConfiguration).not.toHaveBeenCalled(); - expect(mockContextService.setup).toHaveBeenCalled(); - expect(mockHttpService.setup).toHaveBeenCalled(); - expect(mockElasticsearchService.setup).toHaveBeenCalled(); - expect(mockSavedObjectsService.setup).toHaveBeenCalled(); -}); diff --git a/src/core/server/server.ts b/src/core/server/server.ts index ef5164a8c48e18..8905bcd28fe17c 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -120,13 +120,10 @@ export class Server { }); const legacyConfigSetup = await this.legacy.setupLegacyConfig(); - // rely on dev server to validate config, don't validate in the parent process - if (!this.env.isDevCliParent) { - // Immediately terminate in case of invalid configuration - // This needs to be done after plugin discovery - await this.configService.validate(); - await ensureValidConfiguration(this.configService, legacyConfigSetup); - } + // Immediately terminate in case of invalid configuration + // This needs to be done after plugin discovery + await this.configService.validate(); + await ensureValidConfiguration(this.configService, legacyConfigSetup); const contextServiceSetup = this.context.setup({ // We inject a fake "legacy plugin" with dependencies on every plugin so that legacy plugins: diff --git a/src/core/test_helpers/kbn_server.ts b/src/core/test_helpers/kbn_server.ts index 5e274712ad3a78..d702fed73778f1 100644 --- a/src/core/test_helpers/kbn_server.ts +++ b/src/core/test_helpers/kbn_server.ts @@ -70,7 +70,6 @@ export function createRootWithSettings( dist: false, ...cliArgs, }, - isDevCliParent: false, }); return new Root( diff --git a/src/dev/cli_dev_mode/bootstrap.ts b/src/dev/cli_dev_mode/bootstrap.ts index b8f1a4161d0cd7..eb7a950cdb94be 100644 --- a/src/dev/cli_dev_mode/bootstrap.ts +++ b/src/dev/cli_dev_mode/bootstrap.ts @@ -24,7 +24,6 @@ export async function bootstrapDevMode({ configs, cliArgs }: BootstrapArgs) { const env = Env.createDefault(REPO_ROOT, { configs, cliArgs, - isDevCliParent: true, }); const config = await loadConfig({ From 023c6af23e797242d3b7cf892792d6b23771c50d Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Tue, 23 Mar 2021 20:52:00 +0100 Subject: [PATCH 05/38] choose bootstrap script --- src/cli/serve/serve.js | 60 +++++++++++++++++++------------ src/dev/cli_dev_mode/bootstrap.ts | 7 ++-- src/dev/cli_dev_mode/index.ts | 1 + 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 32aa45f686fca4..6cc1d591d359c5 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -15,7 +15,6 @@ import url from 'url'; import { getConfigPath } from '@kbn/utils'; import { IS_KIBANA_DISTRIBUTABLE } from '../../legacy/utils'; import { fromRoot } from '../../core/server/utils'; -import { bootstrap } from '../../core/server'; import { readKeystore } from '../keystore/read_keystore'; function canRequire(path) { @@ -34,6 +33,16 @@ function canRequire(path) { const DEV_MODE_PATH = resolve(__dirname, '../../dev/cli_dev_mode'); const DEV_MODE_SUPPORTED = canRequire(DEV_MODE_PATH); +const getBootstrapScript = () => { + if (DEV_MODE_SUPPORTED && process.env.isDevCliChild !== 'true') { + const { bootstrapDevMode } = require('../../dev/cli_dev_mode'); + return bootstrapDevMode; + } else { + const { bootstrap } = require('../../core/server'); + return bootstrap; + } +}; + const pathCollector = function () { const paths = []; return function (path) { @@ -78,6 +87,7 @@ function applyConfigOverrides(rawConfig, opts, extraCliOptions) { throw new Error(`Can't use --ssl when "${path}" configuration is already defined.`); } } + ensureNotDefined('server.ssl.certificate'); ensureNotDefined('server.ssl.key'); ensureNotDefined('server.ssl.keystore.path'); @@ -209,28 +219,32 @@ export default function (program) { } const unknownOptions = this.getUnknownOptions(); - await bootstrap({ - configs: [].concat(opts.config || []), - cliArgs: { - dev: !!opts.dev, - envName: unknownOptions.env ? unknownOptions.env.name : undefined, - // no longer supported - quiet: !!opts.quiet, - silent: !!opts.silent, - watch: !!opts.watch, - runExamples: !!opts.runExamples, - // We want to run without base path when the `--run-examples` flag is given so that we can use local - // links in other documentation sources, like "View this tutorial [here](http://localhost:5601/app/tutorial/xyz)". - // We can tell users they only have to run with `yarn start --run-examples` to get those - // local links to work. Similar to what we do for "View in Console" links in our - // elastic.co links. - basePath: opts.runExamples ? false : !!opts.basePath, - optimize: !!opts.optimize, - disableOptimizer: !opts.optimizer, - oss: !!opts.oss, - cache: !!opts.cache, - dist: !!opts.dist, - }, + const configs = [].concat(opts.config || []); + const cliArgs = { + dev: !!opts.dev, + envName: unknownOptions.env ? unknownOptions.env.name : undefined, + // no longer supported + quiet: !!opts.quiet, + silent: !!opts.silent, + watch: !!opts.watch, + runExamples: !!opts.runExamples, + // We want to run without base path when the `--run-examples` flag is given so that we can use local + // links in other documentation sources, like "View this tutorial [here](http://localhost:5601/app/tutorial/xyz)". + // We can tell users they only have to run with `yarn start --run-examples` to get those + // local links to work. Similar to what we do for "View in Console" links in our + // elastic.co links. + basePath: opts.runExamples ? false : !!opts.basePath, + optimize: !!opts.optimize, + disableOptimizer: !opts.optimizer, + oss: !!opts.oss, + cache: !!opts.cache, + dist: !!opts.dist, + }; + const bootstrapScript = getBootstrapScript(); + + await bootstrapScript({ + configs, + cliArgs, applyConfigOverrides: (rawConfig) => applyConfigOverrides(rawConfig, opts, unknownOptions), }); }); diff --git a/src/dev/cli_dev_mode/bootstrap.ts b/src/dev/cli_dev_mode/bootstrap.ts index eb7a950cdb94be..86a276c64f1f55 100644 --- a/src/dev/cli_dev_mode/bootstrap.ts +++ b/src/dev/cli_dev_mode/bootstrap.ts @@ -7,7 +7,7 @@ */ import { REPO_ROOT } from '@kbn/utils'; -import { CliArgs, Env } from '@kbn/config'; +import { CliArgs, Env, RawConfigAdapter } from '@kbn/config'; import { CliDevMode } from './cli_dev_mode'; import { CliLog } from './log'; import { convertToLogger } from './log_adapter'; @@ -16,9 +16,10 @@ import { loadConfig } from './config'; interface BootstrapArgs { configs: string[]; cliArgs: CliArgs; + applyConfigOverrides: RawConfigAdapter; } -export async function bootstrapDevMode({ configs, cliArgs }: BootstrapArgs) { +export async function bootstrapDevMode({ configs, cliArgs, applyConfigOverrides }: BootstrapArgs) { const log = new CliLog(!!cliArgs.quiet, !!cliArgs.silent); const env = Env.createDefault(REPO_ROOT, { @@ -29,7 +30,7 @@ export async function bootstrapDevMode({ configs, cliArgs }: BootstrapArgs) { const config = await loadConfig({ env, logger: convertToLogger(log), - rawConfigAdapter: (cfg) => cfg, // TODO: use from cli/serve + rawConfigAdapter: applyConfigOverrides, }); const cliDevMode = new CliDevMode({ diff --git a/src/dev/cli_dev_mode/index.ts b/src/dev/cli_dev_mode/index.ts index 561cc8acf07ae7..47bbca045671d2 100644 --- a/src/dev/cli_dev_mode/index.ts +++ b/src/dev/cli_dev_mode/index.ts @@ -8,3 +8,4 @@ export { CliDevMode, CliDevModeOptions, SomeCliArgs } from './cli_dev_mode'; export { Log, CliLog, TestLog } from './log'; +export { bootstrapDevMode } from './bootstrap'; From 38ab1af63c42f250750ffad4f20a1a7d20c8ac92 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 08:00:39 +0100 Subject: [PATCH 06/38] fix bootstrap script logic --- src/cli/serve/serve.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 6cc1d591d359c5..ed05bcaf38ffb9 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -33,8 +33,8 @@ function canRequire(path) { const DEV_MODE_PATH = resolve(__dirname, '../../dev/cli_dev_mode'); const DEV_MODE_SUPPORTED = canRequire(DEV_MODE_PATH); -const getBootstrapScript = () => { - if (DEV_MODE_SUPPORTED && process.env.isDevCliChild !== 'true') { +const getBootstrapScript = (isDev) => { + if (DEV_MODE_SUPPORTED && isDev && process.env.isDevCliChild !== 'true') { const { bootstrapDevMode } = require('../../dev/cli_dev_mode'); return bootstrapDevMode; } else { @@ -240,7 +240,7 @@ export default function (program) { cache: !!opts.cache, dist: !!opts.dist, }; - const bootstrapScript = getBootstrapScript(); + const bootstrapScript = getBootstrapScript(cliArgs.dev); await bootstrapScript({ configs, From fb098c08137821e657ba79f7a97cca29a3984601 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 08:15:33 +0100 Subject: [PATCH 07/38] fix watch paths logic --- src/cli/serve/serve.js | 4 +++- src/dev/cli_dev_mode/get_server_watch_paths.ts | 10 +--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index ed05bcaf38ffb9..cc592d53230bcf 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -13,10 +13,12 @@ import { resolve } from 'path'; import url from 'url'; import { getConfigPath } from '@kbn/utils'; +import { REPO_ROOT } from '@kbn/dev-utils'; import { IS_KIBANA_DISTRIBUTABLE } from '../../legacy/utils'; -import { fromRoot } from '../../core/server/utils'; import { readKeystore } from '../keystore/read_keystore'; +const fromRoot = (p) => resolve(REPO_ROOT, p); + function canRequire(path) { try { require.resolve(path); diff --git a/src/dev/cli_dev_mode/get_server_watch_paths.ts b/src/dev/cli_dev_mode/get_server_watch_paths.ts index 46aa15659a5139..53aa53b5aa63a5 100644 --- a/src/dev/cli_dev_mode/get_server_watch_paths.ts +++ b/src/dev/cli_dev_mode/get_server_watch_paths.ts @@ -47,15 +47,7 @@ export function getServerWatchPaths({ pluginPaths, pluginScanDirs }: Options) { ...pluginScanDirs, ].map((path) => Path.resolve(path)) ) - ); - - for (const watchPath of watchPaths) { - if (!Fs.existsSync(fromRoot(watchPath))) { - throw new Error( - `A watch directory [${watchPath}] does not exist, which will cause chokidar to fail. Either make sure the directory exists or remove it as a watch source in the ClusterManger` - ); - } - } + ).filter((path) => Fs.existsSync(fromRoot(path))); const ignorePaths = [ /[\\\/](\..*|node_modules|bower_components|target|public|__[a-z0-9_]+__|coverage)([\\\/]|$)/, From 0967c20e264d51963278a6fde4b0876dc0bce45f Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 08:59:36 +0100 Subject: [PATCH 08/38] import REPO_ROOT from correct package --- src/cli/serve/serve.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index cc592d53230bcf..4f77aa687a690e 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -12,8 +12,7 @@ import { statSync } from 'fs'; import { resolve } from 'path'; import url from 'url'; -import { getConfigPath } from '@kbn/utils'; -import { REPO_ROOT } from '@kbn/dev-utils'; +import { getConfigPath, REPO_ROOT } from '@kbn/utils'; import { IS_KIBANA_DISTRIBUTABLE } from '../../legacy/utils'; import { readKeystore } from '../keystore/read_keystore'; From 54ee08aee0c8cf3aefd101ac4d5109b67f3155b4 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 09:26:21 +0100 Subject: [PATCH 09/38] create the @kbn/crypto package --- package.json | 1 + packages/kbn-crypto/jest.config.js | 13 +++++++++++++ packages/kbn-crypto/package.json | 16 ++++++++++++++++ .../kbn-crypto/src}/__fixtures__/README.md | 0 .../kbn-crypto/src}/__fixtures__/index.ts | 0 .../kbn-crypto/src}/__fixtures__/no_ca.p12 | Bin .../kbn-crypto/src}/__fixtures__/no_cert.p12 | Bin .../kbn-crypto/src}/__fixtures__/no_key.p12 | Bin .../kbn-crypto/src}/__fixtures__/two_cas.p12 | Bin .../kbn-crypto/src}/__fixtures__/two_keys.p12 | Bin .../crypto => packages/kbn-crypto/src}/index.ts | 0 .../kbn-crypto/src}/pkcs12.test.ts | 2 +- .../kbn-crypto/src}/pkcs12.ts | 0 .../kbn-crypto/src}/sha256.test.ts | 0 .../kbn-crypto/src}/sha256.ts | 0 packages/kbn-crypto/tsconfig.json | 12 ++++++++++++ .../elasticsearch/elasticsearch_config.ts | 2 +- src/core/server/http/ssl_config.ts | 2 +- src/core/server/utils/index.ts | 1 - yarn.lock | 4 ++++ 20 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 packages/kbn-crypto/jest.config.js create mode 100644 packages/kbn-crypto/package.json rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/README.md (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/index.ts (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/no_ca.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/no_cert.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/no_key.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/two_cas.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/two_keys.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/index.ts (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/pkcs12.test.ts (99%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/pkcs12.ts (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/sha256.test.ts (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/sha256.ts (100%) create mode 100644 packages/kbn-crypto/tsconfig.json diff --git a/package.json b/package.json index a34edd2450bc61..a6c5375f7d1399 100644 --- a/package.json +++ b/package.json @@ -122,6 +122,7 @@ "@kbn/apm-utils": "link:packages/kbn-apm-utils", "@kbn/config": "link:packages/kbn-config", "@kbn/config-schema": "link:packages/kbn-config-schema", + "@kbn/crypto": "link:packages/kbn-crypto", "@kbn/http-tools": "link:packages/kbn-http-tools", "@kbn/i18n": "link:packages/kbn-i18n", "@kbn/interpreter": "link:packages/kbn-interpreter", diff --git a/packages/kbn-crypto/jest.config.js b/packages/kbn-crypto/jest.config.js new file mode 100644 index 00000000000000..811b87e5ed0f6e --- /dev/null +++ b/packages/kbn-crypto/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-crypto'], +}; diff --git a/packages/kbn-crypto/package.json b/packages/kbn-crypto/package.json new file mode 100644 index 00000000000000..6c7b3f3b0c719b --- /dev/null +++ b/packages/kbn-crypto/package.json @@ -0,0 +1,16 @@ +{ + "name": "@kbn/crypto", + "version": "1.0.0", + "private": true, + "license": "SSPL-1.0 OR Elastic License 2.0", + "main": "./target/index.js", + "scripts": { + "build": "../../node_modules/.bin/tsc", + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" + }, + "dependencies": {}, + "devDependencies": { + "@kbn/dev-utils": "link:../kbn-dev-utils" + } +} \ No newline at end of file diff --git a/src/core/server/utils/crypto/__fixtures__/README.md b/packages/kbn-crypto/src/__fixtures__/README.md similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/README.md rename to packages/kbn-crypto/src/__fixtures__/README.md diff --git a/src/core/server/utils/crypto/__fixtures__/index.ts b/packages/kbn-crypto/src/__fixtures__/index.ts similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/index.ts rename to packages/kbn-crypto/src/__fixtures__/index.ts diff --git a/src/core/server/utils/crypto/__fixtures__/no_ca.p12 b/packages/kbn-crypto/src/__fixtures__/no_ca.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/no_ca.p12 rename to packages/kbn-crypto/src/__fixtures__/no_ca.p12 diff --git a/src/core/server/utils/crypto/__fixtures__/no_cert.p12 b/packages/kbn-crypto/src/__fixtures__/no_cert.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/no_cert.p12 rename to packages/kbn-crypto/src/__fixtures__/no_cert.p12 diff --git a/src/core/server/utils/crypto/__fixtures__/no_key.p12 b/packages/kbn-crypto/src/__fixtures__/no_key.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/no_key.p12 rename to packages/kbn-crypto/src/__fixtures__/no_key.p12 diff --git a/src/core/server/utils/crypto/__fixtures__/two_cas.p12 b/packages/kbn-crypto/src/__fixtures__/two_cas.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/two_cas.p12 rename to packages/kbn-crypto/src/__fixtures__/two_cas.p12 diff --git a/src/core/server/utils/crypto/__fixtures__/two_keys.p12 b/packages/kbn-crypto/src/__fixtures__/two_keys.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/two_keys.p12 rename to packages/kbn-crypto/src/__fixtures__/two_keys.p12 diff --git a/src/core/server/utils/crypto/index.ts b/packages/kbn-crypto/src/index.ts similarity index 100% rename from src/core/server/utils/crypto/index.ts rename to packages/kbn-crypto/src/index.ts diff --git a/src/core/server/utils/crypto/pkcs12.test.ts b/packages/kbn-crypto/src/pkcs12.test.ts similarity index 99% rename from src/core/server/utils/crypto/pkcs12.test.ts rename to packages/kbn-crypto/src/pkcs12.test.ts index 8c6e5bae3b9c1e..ba8eb6554f7b8b 100644 --- a/src/core/server/utils/crypto/pkcs12.test.ts +++ b/packages/kbn-crypto/src/pkcs12.test.ts @@ -18,7 +18,7 @@ import { import { NO_CA_PATH, NO_CERT_PATH, NO_KEY_PATH, TWO_CAS_PATH, TWO_KEYS_PATH } from './__fixtures__'; import { readFileSync } from 'fs'; -import { readPkcs12Keystore, Pkcs12ReadResult, readPkcs12Truststore } from './index'; +import { readPkcs12Keystore, Pkcs12ReadResult, readPkcs12Truststore } from './pkcs12'; const reformatPem = (pem: string) => { // ensure consistency in line endings when comparing two PEM files diff --git a/src/core/server/utils/crypto/pkcs12.ts b/packages/kbn-crypto/src/pkcs12.ts similarity index 100% rename from src/core/server/utils/crypto/pkcs12.ts rename to packages/kbn-crypto/src/pkcs12.ts diff --git a/src/core/server/utils/crypto/sha256.test.ts b/packages/kbn-crypto/src/sha256.test.ts similarity index 100% rename from src/core/server/utils/crypto/sha256.test.ts rename to packages/kbn-crypto/src/sha256.test.ts diff --git a/src/core/server/utils/crypto/sha256.ts b/packages/kbn-crypto/src/sha256.ts similarity index 100% rename from src/core/server/utils/crypto/sha256.ts rename to packages/kbn-crypto/src/sha256.ts diff --git a/packages/kbn-crypto/tsconfig.json b/packages/kbn-crypto/tsconfig.json new file mode 100644 index 00000000000000..1c6c671d0b7683 --- /dev/null +++ b/packages/kbn-crypto/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target", + "target": "ES2019", + "declaration": true, + "declarationMap": true + }, + "include": [ + "src/**/*" + ] +} diff --git a/src/core/server/elasticsearch/elasticsearch_config.ts b/src/core/server/elasticsearch/elasticsearch_config.ts index 879002a6ece51e..d3432344f5a739 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.ts @@ -7,10 +7,10 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { readPkcs12Keystore, readPkcs12Truststore } from '@kbn/crypto'; import { Duration } from 'moment'; import { readFileSync } from 'fs'; import { ConfigDeprecationProvider } from 'src/core/server'; -import { readPkcs12Keystore, readPkcs12Truststore } from '../utils'; import { ServiceConfigDescriptor } from '../internal_types'; import { getReservedHeaders } from './default_headers'; diff --git a/src/core/server/http/ssl_config.ts b/src/core/server/http/ssl_config.ts index a3984e10cd232e..8da0e5145d0dc8 100644 --- a/src/core/server/http/ssl_config.ts +++ b/src/core/server/http/ssl_config.ts @@ -7,9 +7,9 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { readPkcs12Keystore, readPkcs12Truststore } from '@kbn/crypto'; import { constants as cryptoConstants } from 'crypto'; import { readFileSync } from 'fs'; -import { readPkcs12Keystore, readPkcs12Truststore } from '../utils'; const protocolMap = new Map([ ['TLSv1', cryptoConstants.SSL_OP_NO_TLSv1], diff --git a/src/core/server/utils/index.ts b/src/core/server/utils/index.ts index e2dc2c7d99a93e..b0776c48f3bed2 100644 --- a/src/core/server/utils/index.ts +++ b/src/core/server/utils/index.ts @@ -6,6 +6,5 @@ * Side Public License, v 1. */ -export * from './crypto'; export * from './from_root'; export * from './package_json'; diff --git a/yarn.lock b/yarn.lock index 4a82aea6c42363..dac5d16d61ac27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2625,6 +2625,10 @@ version "0.0.0" uid "" +"@kbn/crypto@link:packages/kbn-crypto": + version "0.0.0" + uid "" + "@kbn/dev-utils@link:packages/kbn-dev-utils": version "0.0.0" uid "" From 1ef4ddd8539f154ec4e742e9e7857231572689b4 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 09:32:13 +0100 Subject: [PATCH 10/38] update core's `dev` config --- src/core/server/dev/dev_config.ts | 23 ++++------------------- src/core/server/dev/index.ts | 3 +-- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/core/server/dev/dev_config.ts b/src/core/server/dev/dev_config.ts index 3a303a61c85637..2fec778d857137 100644 --- a/src/core/server/dev/dev_config.ts +++ b/src/core/server/dev/dev_config.ts @@ -6,26 +6,11 @@ * Side Public License, v 1. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; export const config = { path: 'dev', - schema: schema.object({ - basePathProxyTarget: schema.number({ - defaultValue: 5603, - }), - }), + // dev configuration is validated by the dev cli. + // we only need to register the `dev` schema to avoid failing core's config validation + schema: schema.object({}, { unknowns: 'ignore' }), }; - -export type DevConfigType = TypeOf; - -export class DevConfig { - public basePathProxyTargetPort: number; - - /** - * @internal - */ - constructor(rawConfig: DevConfigType) { - this.basePathProxyTargetPort = rawConfig.basePathProxyTarget; - } -} diff --git a/src/core/server/dev/index.ts b/src/core/server/dev/index.ts index 6e0fd343d2ec84..70257d2a5e6c51 100644 --- a/src/core/server/dev/index.ts +++ b/src/core/server/dev/index.ts @@ -6,5 +6,4 @@ * Side Public License, v 1. */ -export { config, DevConfig } from './dev_config'; -export type { DevConfigType } from './dev_config'; +export { config } from './dev_config'; From d2e1ba03f9e10c692a0cbe2ea13a7371d499e52d Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 09:56:16 +0100 Subject: [PATCH 11/38] only export bootstrap function --- src/dev/cli_dev_mode/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dev/cli_dev_mode/index.ts b/src/dev/cli_dev_mode/index.ts index 47bbca045671d2..98b52087f231a3 100644 --- a/src/dev/cli_dev_mode/index.ts +++ b/src/dev/cli_dev_mode/index.ts @@ -6,6 +6,4 @@ * Side Public License, v 1. */ -export { CliDevMode, CliDevModeOptions, SomeCliArgs } from './cli_dev_mode'; -export { Log, CliLog, TestLog } from './log'; export { bootstrapDevMode } from './bootstrap'; From 6a64c1cccd8f40ab37f4cc8eb70fd8e032db5be3 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 10:04:46 +0100 Subject: [PATCH 12/38] extract sslConfig to http-tools package --- packages/kbn-http-tools/package.json | 1 + packages/kbn-http-tools/src/index.ts | 1 + packages/kbn-http-tools/src/ssl/index.ts | 9 +++++++++ .../kbn-http-tools/src/ssl}/ssl_config.test.mocks.ts | 2 +- .../kbn-http-tools/src/ssl}/ssl_config.test.ts | 2 +- .../kbn-http-tools/src/ssl}/ssl_config.ts | 0 src/core/server/http/http_config.ts | 3 +-- src/dev/cli_dev_mode/config/http_config.ts | 9 +++------ 8 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 packages/kbn-http-tools/src/ssl/index.ts rename {src/core/server/http => packages/kbn-http-tools/src/ssl}/ssl_config.test.mocks.ts (95%) rename {src/core/server/http => packages/kbn-http-tools/src/ssl}/ssl_config.test.ts (99%) rename {src/core/server/http => packages/kbn-http-tools/src/ssl}/ssl_config.ts (100%) diff --git a/packages/kbn-http-tools/package.json b/packages/kbn-http-tools/package.json index 174ee8d97dfec4..12d3a2119b88cc 100644 --- a/packages/kbn-http-tools/package.json +++ b/packages/kbn-http-tools/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@kbn/config-schema": "link:../kbn-config-schema", + "@kbn/crypto": "link:../kbn-crypto", "@kbn/std": "link:../kbn-std" }, "devDependencies": { diff --git a/packages/kbn-http-tools/src/index.ts b/packages/kbn-http-tools/src/index.ts index db52bfb2809633..bd1dffa0bb0cab 100644 --- a/packages/kbn-http-tools/src/index.ts +++ b/packages/kbn-http-tools/src/index.ts @@ -12,3 +12,4 @@ export { defaultValidationErrorHandler } from './default_validation_error_handle export { getListenerOptions } from './get_listener_options'; export { getServerOptions } from './get_server_options'; export { getRequestId } from './get_request_id'; +export { sslSchema, SslConfig } from './ssl'; diff --git a/packages/kbn-http-tools/src/ssl/index.ts b/packages/kbn-http-tools/src/ssl/index.ts new file mode 100644 index 00000000000000..cbc3f17f915efd --- /dev/null +++ b/packages/kbn-http-tools/src/ssl/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { SslConfig, sslSchema } from './ssl_config'; diff --git a/src/core/server/http/ssl_config.test.mocks.ts b/packages/kbn-http-tools/src/ssl/ssl_config.test.mocks.ts similarity index 95% rename from src/core/server/http/ssl_config.test.mocks.ts rename to packages/kbn-http-tools/src/ssl/ssl_config.test.mocks.ts index 81dbcf55100f87..adc4adb76f8047 100644 --- a/src/core/server/http/ssl_config.test.mocks.ts +++ b/packages/kbn-http-tools/src/ssl/ssl_config.test.mocks.ts @@ -13,7 +13,7 @@ jest.mock('fs', () => { export const mockReadPkcs12Keystore = jest.fn(); export const mockReadPkcs12Truststore = jest.fn(); -jest.mock('../utils', () => ({ +jest.mock('@kbn/crypto', () => ({ readPkcs12Keystore: mockReadPkcs12Keystore, readPkcs12Truststore: mockReadPkcs12Truststore, })); diff --git a/src/core/server/http/ssl_config.test.ts b/packages/kbn-http-tools/src/ssl/ssl_config.test.ts similarity index 99% rename from src/core/server/http/ssl_config.test.ts rename to packages/kbn-http-tools/src/ssl/ssl_config.test.ts index bb6b1c7ff29f3e..112fcd8a449f75 100644 --- a/src/core/server/http/ssl_config.test.ts +++ b/packages/kbn-http-tools/src/ssl/ssl_config.test.ts @@ -34,7 +34,7 @@ describe('#SslConfig', () => { beforeEach(() => { const realFs = jest.requireActual('fs'); mockReadFileSync.mockImplementation((path: string) => realFs.readFileSync(path)); - const utils = jest.requireActual('../utils'); + const utils = jest.requireActual('@kbn/crypto'); mockReadPkcs12Keystore.mockImplementation((path: string, password?: string) => utils.readPkcs12Keystore(path, password) ); diff --git a/src/core/server/http/ssl_config.ts b/packages/kbn-http-tools/src/ssl/ssl_config.ts similarity index 100% rename from src/core/server/http/ssl_config.ts rename to packages/kbn-http-tools/src/ssl/ssl_config.ts diff --git a/src/core/server/http/http_config.ts b/src/core/server/http/http_config.ts index 2b8533a78f1c3d..47e9e84e550ece 100644 --- a/src/core/server/http/http_config.ts +++ b/src/core/server/http/http_config.ts @@ -7,13 +7,12 @@ */ import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema'; -import { IHttpConfig } from '@kbn/http-tools'; +import { IHttpConfig, SslConfig, sslSchema } from '@kbn/http-tools'; import { hostname } from 'os'; import url from 'url'; import { CspConfigType, CspConfig, ICspConfig } from '../csp'; import { ExternalUrlConfig, IExternalUrlConfig } from '../external_url'; -import { SslConfig, sslSchema } from './ssl_config'; const validBasePathRegex = /^\/.*[^\/]$/; const uuidRegexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i; diff --git a/src/dev/cli_dev_mode/config/http_config.ts b/src/dev/cli_dev_mode/config/http_config.ts index 1a0b9586dff086..36a3009d27dbe4 100644 --- a/src/dev/cli_dev_mode/config/http_config.ts +++ b/src/dev/cli_dev_mode/config/http_config.ts @@ -7,7 +7,7 @@ */ import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema'; -import { ICorsConfig, IHttpConfig, ISslConfig } from '@kbn/http-tools'; +import { ICorsConfig, IHttpConfig, ISslConfig, SslConfig, sslSchema } from '@kbn/http-tools'; export const httpConfigSchema = schema.object( { @@ -35,7 +35,7 @@ export const httpConfigSchema = schema.object( defaultValue: ['*'], }), }), - // TODO: SSL + ssl: sslSchema, }, { unknowns: 'ignore' } ); @@ -60,9 +60,6 @@ export class HttpConfig implements IHttpConfig { this.keepaliveTimeout = rawConfig.keepaliveTimeout; this.socketTimeout = rawConfig.socketTimeout; this.cors = rawConfig.cors; - // TODO: SSL - this.ssl = { - enabled: false, - }; + this.ssl = new SslConfig(rawConfig.ssl); } } From 790b74a3c51f2d1781da33a2dce384503fdd351c Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 10:45:50 +0100 Subject: [PATCH 13/38] fix core types --- src/core/server/external_url/external_url_config.ts | 2 +- src/core/server/http/http_server.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/server/external_url/external_url_config.ts b/src/core/server/external_url/external_url_config.ts index 7e4afbfbfea05a..da4e8199dc6230 100644 --- a/src/core/server/external_url/external_url_config.ts +++ b/src/core/server/external_url/external_url_config.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { createSHA256Hash } from '../utils'; +import { createSHA256Hash } from '@kbn/crypto'; import { config } from './config'; const DEFAULT_CONFIG = Object.freeze(config.schema.validate({})); diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index 54be7b35f68ad4..6a7dd44a292fb3 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -73,7 +73,7 @@ beforeEach(() => { enabled: true, certificate, cipherSuites: ['TLS_AES_256_GCM_SHA384'], - getSecureOptions: () => 0, + secureOptions: 0, key, redirectHttpFromPort: config.port + 1, }, From 3ddd3e78808c84514858810b6890bd816e664454 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 10:54:14 +0100 Subject: [PATCH 14/38] fix optimizer tests --- src/dev/cli_dev_mode/optimizer.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dev/cli_dev_mode/optimizer.test.ts b/src/dev/cli_dev_mode/optimizer.test.ts index 409ad1a455a57b..c270a00329897a 100644 --- a/src/dev/cli_dev_mode/optimizer.test.ts +++ b/src/dev/cli_dev_mode/optimizer.test.ts @@ -43,6 +43,7 @@ const defaultOptions: Options = { dist: true, oss: true, pluginPaths: ['/some/dir'], + pluginScanDirs: ['/some-scan-path'], quiet: true, silent: true, repoRoot: '/app', @@ -83,6 +84,7 @@ it('uses options to create valid OptimizerConfig', () => { runExamples: false, oss: false, pluginPaths: [], + pluginScanDirs: [], repoRoot: '/foo/bar', watch: false, }); @@ -99,6 +101,9 @@ it('uses options to create valid OptimizerConfig', () => { "pluginPaths": Array [ "/some/dir", ], + "pluginScanDirs": Array [ + "/some-scan-path", + ], "repoRoot": "/app", "watch": true, }, @@ -111,6 +116,7 @@ it('uses options to create valid OptimizerConfig', () => { "includeCoreBundle": true, "oss": false, "pluginPaths": Array [], + "pluginScanDirs": Array [], "repoRoot": "/foo/bar", "watch": false, }, From a25f37ce7aa3280ee90e2e885ba5a6c592b743e2 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 11:29:18 +0100 Subject: [PATCH 15/38] fix cli_dev_mode tests --- src/dev/cli_dev_mode/cli_dev_mode.test.ts | 139 ++++++++++++---------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/src/dev/cli_dev_mode/cli_dev_mode.test.ts b/src/dev/cli_dev_mode/cli_dev_mode.test.ts index 54c49ce21505ff..958ed47c223a63 100644 --- a/src/dev/cli_dev_mode/cli_dev_mode.test.ts +++ b/src/dev/cli_dev_mode/cli_dev_mode.test.ts @@ -7,16 +7,16 @@ */ import Path from 'path'; - +import * as Rx from 'rxjs'; import { REPO_ROOT, createAbsolutePathSerializer, createAnyInstanceSerializer, } from '@kbn/dev-utils'; -import * as Rx from 'rxjs'; import { TestLog } from './log'; -import { CliDevMode } from './cli_dev_mode'; +import { CliDevMode, SomeCliArgs } from './cli_dev_mode'; +import type { CliDevConfig } from './config'; expect.addSnapshotSerializer(createAbsolutePathSerializer()); expect.addSnapshotSerializer(createAnyInstanceSerializer(Rx.Observable, 'Rx.Observable')); @@ -31,6 +31,9 @@ const { Optimizer } = jest.requireMock('./optimizer'); jest.mock('./dev_server'); const { DevServer } = jest.requireMock('./dev_server'); +jest.mock('./base_path_proxy_server'); +const { BasePathProxyServer } = jest.requireMock('./base_path_proxy_server'); + jest.mock('./get_server_watch_paths', () => ({ getServerWatchPaths: jest.fn(() => ({ watchPaths: [''], @@ -38,13 +41,6 @@ jest.mock('./get_server_watch_paths', () => ({ })), })); -beforeEach(() => { - process.argv = ['node', './script', 'foo', 'bar', 'baz']; - jest.clearAllMocks(); -}); - -const log = new TestLog(); - const mockBasePathProxy = { targetPort: 9999, basePath: '/foo/bar', @@ -52,26 +48,53 @@ const mockBasePathProxy = { stop: jest.fn(), }; -const defaultOptions = { +let log: TestLog; + +beforeEach(() => { + process.argv = ['node', './script', 'foo', 'bar', 'baz']; + log = new TestLog(); + BasePathProxyServer.mockImplementation(() => mockBasePathProxy); +}); + +afterEach(() => { + jest.clearAllMocks(); + mockBasePathProxy.start.mockReset(); + mockBasePathProxy.stop.mockReset(); +}); + +const createCliArgs = (parts: Partial = {}): SomeCliArgs => ({ + basePath: false, cache: true, disableOptimizer: false, dist: true, oss: true, - pluginPaths: [], - pluginScanDirs: [Path.resolve(REPO_ROOT, 'src/plugins')], - quiet: false, - silent: false, runExamples: false, watch: true, - log, -}; + silent: false, + quiet: false, + ...parts, +}); -afterEach(() => { - log.messages.length = 0; +const createDevConfig = (parts: Partial = {}): CliDevConfig => ({ + plugins: { + pluginSearchPaths: [Path.resolve(REPO_ROOT, 'src/plugins')], + additionalPluginPaths: [], + }, + dev: { + basePathProxyTargetPort: 9000, + }, + http: {} as any, + ...parts, +}); + +const createOptions = ({ cliArgs = {} }: { cliArgs?: Partial } = {}) => ({ + cliArgs: createCliArgs(cliArgs), + config: createDevConfig(), + log, }); it('passes correct args to sub-classes', () => { - new CliDevMode(defaultOptions); + new CliDevMode(createOptions()); expect(DevServer.mock.calls).toMatchInlineSnapshot(` Array [ @@ -102,6 +125,9 @@ it('passes correct args to sub-classes', () => { "enabled": true, "oss": true, "pluginPaths": Array [], + "pluginScanDirs": Array [ + /src/plugins, + ], "quiet": false, "repoRoot": , "runExamples": false, @@ -128,33 +154,38 @@ it('passes correct args to sub-classes', () => { ], ] `); + + expect(BasePathProxyServer).not.toHaveBeenCalled(); + expect(log.messages).toMatchInlineSnapshot(`Array []`); }); it('disables the optimizer', () => { - new CliDevMode({ - ...defaultOptions, - disableOptimizer: true, - }); + new CliDevMode(createOptions({ cliArgs: { disableOptimizer: true } })); expect(Optimizer.mock.calls[0][0]).toHaveProperty('enabled', false); }); it('disables the watcher', () => { - new CliDevMode({ - ...defaultOptions, - watch: false, - }); + new CliDevMode(createOptions({ cliArgs: { watch: false } })); expect(Optimizer.mock.calls[0][0]).toHaveProperty('watch', false); expect(Watcher.mock.calls[0][0]).toHaveProperty('enabled', false); }); -it('overrides the basePath of the server when basePathProxy is defined', () => { - new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }); +it('enable the basePath proxy', () => { + new CliDevMode(createOptions({ cliArgs: { basePath: true } })); + + expect(BasePathProxyServer).toHaveBeenCalledTimes(1); + expect(BasePathProxyServer.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + , + Object {}, + Object { + "basePathProxyTargetPort": 9000, + }, + ] + `); expect(DevServer.mock.calls[0][0].argv).toMatchInlineSnapshot(` Array [ @@ -221,9 +252,7 @@ describe('#start()/#stop()', () => { }); it('logs a warning if basePathProxy is not passed', () => { - new CliDevMode({ - ...defaultOptions, - }).start(); + new CliDevMode(createOptions()).start(); expect(log.messages).toMatchInlineSnapshot(` Array [ @@ -253,16 +282,9 @@ describe('#start()/#stop()', () => { }); it('calls start on BasePathProxy if enabled', () => { - const basePathProxy: any = { - start: jest.fn(), - }; + new CliDevMode(createOptions({ cliArgs: { basePath: true } })).start(); - new CliDevMode({ - ...defaultOptions, - basePathProxy, - }).start(); - - expect(basePathProxy.start.mock.calls).toMatchInlineSnapshot(` + expect(mockBasePathProxy.start.mock.calls).toMatchInlineSnapshot(` Array [ Array [ Object { @@ -275,7 +297,7 @@ describe('#start()/#stop()', () => { }); it('subscribes to Optimizer#run$, Watcher#run$, and DevServer#run$', () => { - new CliDevMode(defaultOptions).start(); + new CliDevMode(createOptions()).start(); expect(optimizerRun$.observers).toHaveLength(1); expect(watcherRun$.observers).toHaveLength(1); @@ -283,10 +305,7 @@ describe('#start()/#stop()', () => { }); it('logs an error and exits the process if Optimizer#run$ errors', () => { - new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }).start(); + new CliDevMode(createOptions({ cliArgs: { basePath: true } })).start(); expect(processExitMock).not.toHaveBeenCalled(); optimizerRun$.error({ stack: 'Error: foo bar' }); @@ -311,10 +330,7 @@ describe('#start()/#stop()', () => { }); it('logs an error and exits the process if Watcher#run$ errors', () => { - new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }).start(); + new CliDevMode(createOptions({ cliArgs: { basePath: true } })).start(); expect(processExitMock).not.toHaveBeenCalled(); watcherRun$.error({ stack: 'Error: foo bar' }); @@ -339,10 +355,7 @@ describe('#start()/#stop()', () => { }); it('logs an error and exits the process if DevServer#run$ errors', () => { - new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }).start(); + new CliDevMode(createOptions({ cliArgs: { basePath: true } })).start(); expect(processExitMock).not.toHaveBeenCalled(); devServerRun$.error({ stack: 'Error: foo bar' }); @@ -368,10 +381,7 @@ describe('#start()/#stop()', () => { it('throws if start() has already been called', () => { expect(() => { - const devMode = new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }); + const devMode = new CliDevMode(createOptions({ cliArgs: { basePath: true } })); devMode.start(); devMode.start(); @@ -379,10 +389,7 @@ describe('#start()/#stop()', () => { }); it('unsubscribes from all observables and stops basePathProxy when stopped', () => { - const devMode = new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }); + const devMode = new CliDevMode(createOptions({ cliArgs: { basePath: true } })); devMode.start(); devMode.stop(); From f4892b4f0c189df29795724f95b7f04db15cb349 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 17:07:33 +0100 Subject: [PATCH 16/38] fix basePath proxy tests --- .../base_path_proxy_server.test.ts | 859 ++---------------- .../cli_dev_mode/base_path_proxy_server.ts | 2 +- 2 files changed, 99 insertions(+), 762 deletions(-) diff --git a/src/dev/cli_dev_mode/base_path_proxy_server.test.ts b/src/dev/cli_dev_mode/base_path_proxy_server.test.ts index 80c03a2af9031b..3554bc2982757e 100644 --- a/src/dev/cli_dev_mode/base_path_proxy_server.test.ts +++ b/src/dev/cli_dev_mode/base_path_proxy_server.test.ts @@ -6,26 +6,15 @@ * Side Public License, v 1. */ -import { BasePathProxyServer, BasePathProxyServerOptions } from './base_path_proxy_server'; -import { loggingSystemMock } from '../logging/logging_system.mock'; -import { DevConfig } from '../dev/dev_config'; +import { Server } from '@hapi/hapi'; import { EMPTY } from 'rxjs'; -import { HttpConfig } from './http_config'; -import { ByteSizeValue, schema } from '@kbn/config-schema'; -import { - KibanaRequest, - KibanaResponseFactory, - Router, - RouteValidationFunction, - RouteValidationResultFactory, -} from './router'; -import { HttpServer } from './http_server'; import supertest from 'supertest'; -import { RequestHandlerContext } from 'kibana/server'; -import { readFileSync } from 'fs'; -import { KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils'; -import { omit } from 'lodash'; -import { Readable } from 'stream'; +import { getServerOptions, getListenerOptions, createServer, IHttpConfig } from '@kbn/http-tools'; +import { ByteSizeValue } from '@kbn/config-schema'; + +import { BasePathProxyServer, BasePathProxyServerOptions } from './base_path_proxy_server'; +import { DevConfig } from './config/dev_config'; +import { TestLog } from './log'; /** * Most of these tests are inspired by: @@ -33,35 +22,19 @@ import { Readable } from 'stream'; * and copied for completeness from that file. The modifications are that these tests use the developer proxy. */ describe('BasePathProxyServer', () => { - let server: HttpServer; + let server: Server; let proxyServer: BasePathProxyServer; - let config: HttpConfig; - let configWithSSL: HttpConfig; + let logger: TestLog; + let config: IHttpConfig; let basePath: string; - let certificate: string; - let key: string; let proxySupertest: supertest.SuperTest; - const logger = loggingSystemMock.createLogger(); - const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, {}); - - beforeAll(() => { - certificate = readFileSync(KBN_CERT_PATH, 'utf8'); - key = readFileSync(KBN_KEY_PATH, 'utf8'); - }); beforeEach(async () => { - // setup the server but don't start it until each individual test so that routes can be dynamically configured per unit test. - server = new HttpServer(logger, 'tests'); - config = ({ - name: 'kibana', + logger = new TestLog(); + + config = { host: '127.0.0.1', port: 10012, - compression: { enabled: true }, - requestId: { - allowFromAnyIp: true, - ipAllowlist: [], - }, - autoListen: true, keepaliveTimeout: 1000, socketTimeout: 1000, cors: { @@ -70,28 +43,18 @@ describe('BasePathProxyServer', () => { allowOrigin: [], }, ssl: { enabled: false }, - customResponseHeaders: {}, maxPayload: new ByteSizeValue(1024), - rewriteBasePath: true, - } as unknown) as HttpConfig; - - configWithSSL = { - ...config, - ssl: { - enabled: true, - certificate, - cipherSuites: ['TLS_AES_256_GCM_SHA384'], - getSecureOptions: () => 0, - key, - redirectHttpFromPort: config.port + 1, - }, - } as HttpConfig; + }; + + const serverOptions = getServerOptions(config); + const listenerOptions = getListenerOptions(config); + server = createServer(serverOptions, listenerOptions); // setup and start the proxy server - const proxyConfig: HttpConfig = { ...config, port: 10013 }; + const proxyConfig: IHttpConfig = { ...config, port: 10013 }; const devConfig = new DevConfig({ basePathProxyTarget: config.port }); proxyServer = new BasePathProxyServer(logger, proxyConfig, devConfig); - const options: Readonly = { + const options: BasePathProxyServerOptions = { shouldRedirectFromOldBasePath: () => true, delayUntil: () => EMPTY, }; @@ -122,23 +85,14 @@ describe('BasePathProxyServer', () => { expect(location).toMatch(/[a-z]{3}/); }); - test('valid params', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - router.get( - { - path: '/{test}', - validate: { - params: schema.object({ - test: schema.string(), - }), - }, + test('forwards request with the correct path', async () => { + server.route({ + method: 'GET', + path: `${basePath}/foo/{test}`, + handler: (request, h) => { + return h.response(request.params.test); }, - (_, req, res) => { - return res.ok({ body: req.params.test }); - } - ); - const { registerRouter } = await server.setup(config); - registerRouter(router); + }); await server.start(); await proxySupertest @@ -149,60 +103,14 @@ describe('BasePathProxyServer', () => { }); }); - test('invalid params', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.get( - { - path: '/{test}', - validate: { - params: schema.object({ - test: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: String(req.params.test) }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .get(`${basePath}/foo/some-string`) - .expect(400) - .then((res) => { - expect(res.body).toEqual({ - error: 'Bad Request', - statusCode: 400, - message: '[request params.test]: expected value of type [number] but got [string]', - }); - }); - }); - - test('valid query', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.get( - { - path: '/', - validate: { - query: schema.object({ - bar: schema.string(), - quux: schema.number(), - }), - }, + test('forwards request with the correct query params', async () => { + server.route({ + method: 'GET', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response(request.query); }, - (_, req, res) => { - return res.ok({ body: req.query }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); + }); await server.start(); @@ -210,64 +118,18 @@ describe('BasePathProxyServer', () => { .get(`${basePath}/foo/?bar=test&quux=123`) .expect(200) .then((res) => { - expect(res.body).toEqual({ bar: 'test', quux: 123 }); - }); - }); - - test('invalid query', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.get( - { - path: '/', - validate: { - query: schema.object({ - bar: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.query }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .get(`${basePath}/foo/?bar=test`) - .expect(400) - .then((res) => { - expect(res.body).toEqual({ - error: 'Bad Request', - statusCode: 400, - message: '[request query.bar]: expected value of type [number] but got [string]', - }); + expect(res.body).toEqual({ bar: 'test', quux: '123' }); }); }); - test('valid body', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.post( - { - path: '/', - validate: { - body: schema.object({ - bar: schema.string(), - baz: schema.number(), - }), - }, + test('forwards the request body', async () => { + server.route({ + method: 'POST', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response(request.payload); }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); + }); await server.start(); @@ -283,120 +145,57 @@ describe('BasePathProxyServer', () => { }); }); - test('valid body with validate function', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.post( - { - path: '/', - validate: { - body: ({ bar, baz } = {}, { ok, badRequest }) => { - if (typeof bar === 'string' && typeof baz === 'number') { - return ok({ bar, baz }); - } else { - return badRequest('Wrong payload', ['body']); - } - }, - }, + test('returns the correct status code', async () => { + server.route({ + method: 'GET', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response({ foo: 'bar' }).code(417); }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); + }); await server.start(); await proxySupertest - .post(`${basePath}/foo/`) - .send({ - bar: 'test', - baz: 123, - }) - .expect(200) + .get(`${basePath}/foo/`) + .expect(417) .then((res) => { - expect(res.body).toEqual({ bar: 'test', baz: 123 }); + expect(res.body).toEqual({ foo: 'bar' }); }); }); - test('not inline validation - specifying params', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - const bodyValidation = ( - { bar, baz }: any = {}, - { ok, badRequest }: RouteValidationResultFactory - ) => { - if (typeof bar === 'string' && typeof baz === 'number') { - return ok({ bar, baz }); - } else { - return badRequest('Wrong payload', ['body']); - } - }; - - router.post( - { - path: '/', - validate: { - body: bodyValidation, - }, + test('returns the response headers', async () => { + server.route({ + method: 'GET', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response({ foo: 'bar' }).header('foo', 'bar'); }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); + }); await server.start(); await proxySupertest - .post(`${basePath}/foo/`) - .send({ - bar: 'test', - baz: 123, - }) + .get(`${basePath}/foo/`) .expect(200) .then((res) => { - expect(res.body).toEqual({ bar: 'test', baz: 123 }); + expect(res.get('foo')).toEqual('bar'); }); }); - test('not inline validation - specifying validation handler', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - const bodyValidation: RouteValidationFunction<{ bar: string; baz: number }> = ( - { bar, baz } = {}, - { ok, badRequest } - ) => { - if (typeof bar === 'string' && typeof baz === 'number') { - return ok({ bar, baz }); - } else { - return badRequest('Wrong payload', ['body']); - } - }; - - router.post( - { - path: '/', - validate: { - body: bodyValidation, - }, + test('handles putting', async () => { + server.route({ + method: 'PUT', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response(request.payload); }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); + }); await server.start(); await proxySupertest - .post(`${basePath}/foo/`) + .put(`${basePath}/foo/`) .send({ bar: 'test', baz: 123, @@ -407,167 +206,50 @@ describe('BasePathProxyServer', () => { }); }); - test('not inline handler - KibanaRequest', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - const handler = ( - context: RequestHandlerContext, - req: KibanaRequest, - res: KibanaResponseFactory - ) => { - const body = { - bar: req.body.bar.toUpperCase(), - baz: req.body.baz.toString(), - }; - - return res.ok({ body }); - }; - - router.post( - { - path: '/', - validate: { - body: ({ bar, baz } = {}, { ok, badRequest }) => { - if (typeof bar === 'string' && typeof baz === 'number') { - return ok({ bar, baz }); - } else { - return badRequest('Wrong payload', ['body']); - } - }, - }, - }, - handler - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .post(`${basePath}/foo/`) - .send({ - bar: 'test', - baz: 123, - }) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ bar: 'TEST', baz: '123' }); - }); - }); - - test('invalid body', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.post( - { - path: '/', - validate: { - body: schema.object({ - bar: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .post(`${basePath}/foo/`) - .send({ bar: 'test' }) - .expect(400) - .then((res) => { - expect(res.body).toEqual({ - error: 'Bad Request', - statusCode: 400, - message: '[request body.bar]: expected value of type [number] but got [string]', - }); - }); - }); - - test('handles putting', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.put( - { - path: '/', - validate: { - body: schema.object({ - key: schema.string(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .put(`${basePath}/foo/`) - .send({ key: 'new value' }) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ key: 'new value' }); - }); - }); - test('handles deleting', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.delete( - { - path: '/{id}', - validate: { - params: schema.object({ - id: schema.number(), - }), - }, + server.route({ + method: 'DELETE', + path: `${basePath}/foo/{test}`, + handler: (request, h) => { + return h.response(request.params.test); }, - (_, req, res) => { - return res.ok({ body: { key: req.params.id } }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - + }); await server.start(); await proxySupertest - .delete(`${basePath}/foo/3`) + .delete(`${basePath}/foo/some-string`) .expect(200) .then((res) => { - expect(res.body).toEqual({ key: 3 }); + expect(res.text).toBe('some-string'); }); }); describe('with `basepath: /bar` and `rewriteBasePath: false`', () => { - let configWithBasePath: HttpConfig; - beforeEach(async () => { - configWithBasePath = { + const configWithBasePath: IHttpConfig = { ...config, basePath: '/bar', rewriteBasePath: false, - } as HttpConfig; + } as IHttpConfig; - const router = new Router(`${basePath}/`, logger, enhanceWithContext); - router.get({ path: '/', validate: false }, (_, __, res) => res.ok({ body: 'value:/' })); - router.get({ path: '/foo', validate: false }, (_, __, res) => res.ok({ body: 'value:/foo' })); + const serverOptions = getServerOptions(configWithBasePath); + const listenerOptions = getListenerOptions(configWithBasePath); + server = createServer(serverOptions, listenerOptions); - const { registerRouter } = await server.setup(configWithBasePath); - registerRouter(router); + server.route({ + method: 'GET', + path: `${basePath}/`, + handler: (request, h) => { + return h.response('value:/'); + }, + }); + server.route({ + method: 'GET', + path: `${basePath}/foo`, + handler: (request, h) => { + return h.response('value:/foo'); + }, + }); await server.start(); }); @@ -603,358 +285,13 @@ describe('BasePathProxyServer', () => { }); }); - test('with defined `redirectHttpFromPort`', async () => { - const router = new Router(`${basePath}/`, logger, enhanceWithContext); - router.get({ path: '/', validate: false }, (_, __, res) => res.ok({ body: 'value:/' })); - - const { registerRouter } = await server.setup(configWithSSL); - registerRouter(router); - - await server.start(); - }); - - test('allows attaching metadata to attach meta-data tag strings to a route', async () => { - const tags = ['my:tag']; - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.get({ path: '/with-tags', validate: false, options: { tags } }, (_, req, res) => - res.ok({ body: { tags: req.route.options.tags } }) - ); - router.get({ path: '/without-tags', validate: false }, (_, req, res) => - res.ok({ body: { tags: req.route.options.tags } }) - ); - registerRouter(router); - - await server.start(); - await proxySupertest.get(`${basePath}/with-tags`).expect(200, { tags }); - - await proxySupertest.get(`${basePath}/without-tags`).expect(200, { tags: [] }); - }); - - describe('response headers', () => { - test('default headers', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.get({ path: '/', validate: false }, (_, req, res) => res.ok({ body: req.route })); - registerRouter(router); - - await server.start(); - const response = await proxySupertest.get(`${basePath}/`).expect(200); - - const restHeaders = omit(response.header, ['date', 'content-length']); - expect(restHeaders).toMatchInlineSnapshot(` - Object { - "accept-ranges": "bytes", - "cache-control": "private, no-cache, no-store, must-revalidate", - "connection": "close", - "content-type": "application/json; charset=utf-8", - } - `); - }); - }); - - test('exposes route details of incoming request to a route handler (POST + payload options)', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.post( - { - path: '/', - validate: { body: schema.object({ test: schema.number() }) }, - options: { body: { accepts: 'application/json' } }, - }, - (_, req, res) => res.ok({ body: req.route }) - ); - registerRouter(router); - - await server.start(); - await proxySupertest - .post(`${basePath}/`) - .send({ test: 1 }) - .expect(200, { - method: 'post', - path: `${basePath}/`, - options: { - authRequired: true, - xsrfRequired: true, - tags: [], - timeout: { - payload: 10000, - idleSocket: 1000, - }, - body: { - parse: true, // hapi populates the default - maxBytes: 1024, // hapi populates the default - accepts: ['application/json'], - output: 'data', - }, - }, - }); - }); - - test('should return a stream in the body', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.put( - { - path: '/', - validate: { body: schema.stream() }, - options: { body: { output: 'stream' } }, - }, - (_, req, res) => { - expect(req.body).toBeInstanceOf(Readable); - return res.ok({ body: req.route.options.body }); - } - ); - registerRouter(router); - - await server.start(); - await proxySupertest.put(`${basePath}/`).send({ test: 1 }).expect(200, { - parse: true, - maxBytes: 1024, // hapi populates the default - output: 'stream', - }); - }); - - describe('timeout options', () => { - describe('payload timeout', () => { - test('POST routes set the payload timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.post( - { - path: '/', - validate: false, - options: { - timeout: { - payload: 300000, - }, - }, - }, - (_, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - await server.start(); - await proxySupertest - .post(`${basePath}/`) - .send({ test: 1 }) - .expect(200, { - timeout: { - payload: 300000, - idleSocket: 1000, // This is an extra option added by the proxy - }, - }); - }); - - test('DELETE routes set the payload timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.delete( - { - path: '/', - validate: false, - options: { - timeout: { - payload: 300000, - }, - }, - }, - (context, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - await server.start(); - await proxySupertest.delete(`${basePath}/`).expect(200, { - timeout: { - payload: 300000, - idleSocket: 1000, // This is an extra option added by the proxy - }, - }); - }); - - test('PUT routes set the payload timeout and automatically adjusts the idle socket timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.put( - { - path: '/', - validate: false, - options: { - timeout: { - payload: 300000, - }, - }, - }, - (_, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - await server.start(); - await proxySupertest.put(`${basePath}/`).expect(200, { - timeout: { - payload: 300000, - idleSocket: 1000, // This is an extra option added by the proxy - }, - }); - }); - - test('PATCH routes set the payload timeout and automatically adjusts the idle socket timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.patch( - { - path: '/', - validate: false, - options: { - timeout: { - payload: 300000, - }, - }, - }, - (_, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - await server.start(); - await proxySupertest.patch(`${basePath}/`).expect(200, { - timeout: { - payload: 300000, - idleSocket: 1000, // This is an extra option added by the proxy - }, - }); - }); - }); - - describe('idleSocket timeout', () => { - test('uses server socket timeout when not specified in the route', async () => { - const { registerRouter } = await server.setup({ - ...config, - socketTimeout: 11000, - }); - - const router = new Router(basePath, logger, enhanceWithContext); - router.get( - { - path: '/', - validate: { body: schema.maybe(schema.any()) }, - }, - (_, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - - await server.start(); - await proxySupertest - .get(`${basePath}/`) - .send() - .expect(200, { - timeout: { - idleSocket: 11000, - }, - }); - }); - - test('sets the socket timeout when specified in the route', async () => { - const { registerRouter } = await server.setup({ - ...config, - socketTimeout: 11000, - }); - - const router = new Router(basePath, logger, enhanceWithContext); - router.get( - { - path: '/', - validate: { body: schema.maybe(schema.any()) }, - options: { timeout: { idleSocket: 12000 } }, - }, - (context, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - - await server.start(); - await proxySupertest - .get(`${basePath}/`) - .send() - .expect(200, { - timeout: { - idleSocket: 12000, - }, - }); - }); - - test('idleSocket timeout can be smaller than the payload timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.post( - { - path: `${basePath}/`, - validate: { body: schema.any() }, - options: { - timeout: { - payload: 1000, - idleSocket: 10, - }, - }, - }, - (_, req, res) => { - return res.ok({ body: { timeout: req.route.options.timeout } }); - } - ); - - registerRouter(router); - - await server.start(); - }); - }); - }); - describe('shouldRedirect', () => { let proxyServerWithoutShouldRedirect: BasePathProxyServer; let proxyWithoutShouldRedirectSupertest: supertest.SuperTest; beforeEach(async () => { // setup and start a proxy server which does not use "shouldRedirectFromOldBasePath" - const proxyConfig: HttpConfig = { ...config, port: 10004 }; + const proxyConfig: IHttpConfig = { ...config, port: 10004 }; const devConfig = new DevConfig({ basePathProxyTarget: config.port }); proxyServerWithoutShouldRedirect = new BasePathProxyServer(logger, proxyConfig, devConfig); const options: Readonly = { @@ -997,7 +334,7 @@ describe('BasePathProxyServer', () => { beforeEach(async () => { // setup and start a proxy server which uses a basePath of "foo" - const proxyConfig: HttpConfig = { ...config, port: 10004, basePath: '/foo' }; // <-- "foo" here in basePath + const proxyConfig = { ...config, port: 10004, basePath: '/foo' }; // <-- "foo" here in basePath const devConfig = new DevConfig({ basePathProxyTarget: config.port }); proxyServerWithFooBasePath = new BasePathProxyServer(logger, proxyConfig, devConfig); const options: Readonly = { diff --git a/src/dev/cli_dev_mode/base_path_proxy_server.ts b/src/dev/cli_dev_mode/base_path_proxy_server.ts index d8abf915008420..8d2c03762f4b99 100644 --- a/src/dev/cli_dev_mode/base_path_proxy_server.ts +++ b/src/dev/cli_dev_mode/base_path_proxy_server.ts @@ -62,7 +62,7 @@ export class BasePathProxyServer { return this.httpConfig.port; } - public async start(options: Readonly) { + public async start(options: BasePathProxyServerOptions) { this.log.good('starting basepath proxy server'); const serverOptions = getServerOptions(this.httpConfig); From 783e4f7d904bd96c5910a9307da503d0b48072ca Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 18:27:50 +0100 Subject: [PATCH 17/38] update generated doc --- .../kibana-plugin-core-server.kibanaresponsefactory.md | 4 ++-- src/core/server/server.api.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaresponsefactory.md b/docs/development/core/server/kibana-plugin-core-server.kibanaresponsefactory.md index 551cbe3c937504..395c26a6e4bf65 100644 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaresponsefactory.md +++ b/docs/development/core/server/kibana-plugin-core-server.kibanaresponsefactory.md @@ -10,10 +10,10 @@ Set of helpers used to create `KibanaResponse` to form HTTP response on an incom ```typescript kibanaResponseFactory: { - custom: | Buffer | Error | Stream | { + custom: | Error | Buffer | { message: string | Error; attributes?: Record | undefined; - } | undefined>(options: CustomHttpResponseOptions) => KibanaResponse; + } | Stream | undefined>(options: CustomHttpResponseOptions) => KibanaResponse; badRequest: (options?: ErrorHttpResponseOptions) => KibanaResponse; unauthorized: (options?: ErrorHttpResponseOptions) => KibanaResponse; forbidden: (options?: ErrorHttpResponseOptions) => KibanaResponse; diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 580315973ce8fb..d91d082fdcd20a 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -296,7 +296,7 @@ export class BasePath { // Warning: (ae-forgotten-export) The symbol "BootstrapArgs" needs to be exported by the entry point index.d.ts // // @internal (undocumented) -export function bootstrap({ configs, cliArgs, applyConfigOverrides, features, }: BootstrapArgs): Promise; +export function bootstrap({ configs, cliArgs, applyConfigOverrides }: BootstrapArgs): Promise; // @public export interface Capabilities { @@ -342,7 +342,7 @@ export const config: { pingTimeout: Type; logQueries: Type; ssl: import("@kbn/config-schema").ObjectType<{ - verificationMode: Type<"none" | "certificate" | "full">; + verificationMode: Type<"certificate" | "none" | "full">; certificateAuthorities: Type; certificate: Type; key: Type; @@ -1258,10 +1258,10 @@ export type KibanaResponseFactory = typeof kibanaResponseFactory; // @public export const kibanaResponseFactory: { - custom: | Buffer | Error | Stream | { + custom: | Error | Buffer | { message: string | Error; attributes?: Record | undefined; - } | undefined>(options: CustomHttpResponseOptions) => KibanaResponse; + } | Stream | undefined>(options: CustomHttpResponseOptions) => KibanaResponse; badRequest: (options?: ErrorHttpResponseOptions) => KibanaResponse; unauthorized: (options?: ErrorHttpResponseOptions) => KibanaResponse; forbidden: (options?: ErrorHttpResponseOptions) => KibanaResponse; From a7a0b1f669a8d23b8e0c3975dfcf7e31649a722f Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Mar 2021 18:41:45 +0100 Subject: [PATCH 18/38] fix unit tests --- .../server/elasticsearch/elasticsearch_config.test.mocks.ts | 2 +- src/core/server/elasticsearch/elasticsearch_config.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.mocks.ts b/src/core/server/elasticsearch/elasticsearch_config.test.mocks.ts index 32602849d2e450..63b2233b06a967 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.test.mocks.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.test.mocks.ts @@ -11,7 +11,7 @@ jest.mock('fs', () => ({ readFileSync: mockReadFileSync })); export const mockReadPkcs12Keystore = jest.fn(); export const mockReadPkcs12Truststore = jest.fn(); -jest.mock('../utils', () => ({ +jest.mock('@kbn/crypto', () => ({ readPkcs12Keystore: mockReadPkcs12Keystore, readPkcs12Truststore: mockReadPkcs12Truststore, })); diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.ts b/src/core/server/elasticsearch/elasticsearch_config.test.ts index d3f9693bab229d..0efe12df981feb 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.test.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.test.ts @@ -244,7 +244,7 @@ describe('throws when config is invalid', () => { beforeAll(() => { const realFs = jest.requireActual('fs'); mockReadFileSync.mockImplementation((path: string) => realFs.readFileSync(path)); - const utils = jest.requireActual('../utils'); + const utils = jest.requireActual('@kbn/crypto'); mockReadPkcs12Keystore.mockImplementation((path: string, password?: string) => utils.readPkcs12Keystore(path, password) ); From 77e56259106a259fa2bb69497aaf08aa3224cacf Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 25 Mar 2021 08:28:05 +0100 Subject: [PATCH 19/38] create @kbn/dev-cli-mode package --- package.json | 1 + .../kbn-cli-dev-mode}/README.md | 10 +++++--- packages/kbn-cli-dev-mode/jest.config.js | 13 ++++++++++ packages/kbn-cli-dev-mode/package.json | 25 +++++++++++++++++++ .../src}/base_path_proxy_server.test.ts | 0 .../src}/base_path_proxy_server.ts | 0 .../kbn-cli-dev-mode/src}/bootstrap.ts | 0 .../src}/cli_dev_mode.test.ts | 0 .../kbn-cli-dev-mode/src}/cli_dev_mode.ts | 0 .../src}/config/dev_config.ts | 0 .../src}/config/http_config.ts | 0 .../kbn-cli-dev-mode/src}/config/index.ts | 0 .../src}/config/load_config.ts | 0 .../src}/config/plugins_config.ts | 0 .../kbn-cli-dev-mode/src}/config/types.ts | 0 .../kbn-cli-dev-mode/src}/dev_server.test.ts | 0 .../kbn-cli-dev-mode/src}/dev_server.ts | 0 .../src}/get_active_inspect_flag.ts | 0 .../src}/get_server_watch_paths.test.ts | 0 .../src}/get_server_watch_paths.ts | 0 .../kbn-cli-dev-mode/src}/index.ts | 0 .../kbn-cli-dev-mode/src}/log.ts | 0 .../kbn-cli-dev-mode/src}/log_adapter.ts | 0 .../kbn-cli-dev-mode/src}/optimizer.test.ts | 0 .../kbn-cli-dev-mode/src}/optimizer.ts | 0 ...should_redirect_from_old_base_path.test.ts | 0 .../should_redirect_from_old_base_path.ts | 0 .../kbn-cli-dev-mode/src}/test_helpers.ts | 0 .../src}/using_server_process.ts | 0 .../kbn-cli-dev-mode/src}/watcher.test.ts | 0 .../kbn-cli-dev-mode/src}/watcher.ts | 0 packages/kbn-cli-dev-mode/tsconfig.json | 12 +++++++++ src/cli/serve/serve.js | 5 ++-- yarn.lock | 4 +++ 34 files changed, 64 insertions(+), 6 deletions(-) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode}/README.md (72%) create mode 100644 packages/kbn-cli-dev-mode/jest.config.js create mode 100644 packages/kbn-cli-dev-mode/package.json rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/base_path_proxy_server.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/base_path_proxy_server.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/bootstrap.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/cli_dev_mode.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/cli_dev_mode.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/config/dev_config.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/config/http_config.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/config/index.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/config/load_config.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/config/plugins_config.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/config/types.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/dev_server.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/dev_server.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/get_active_inspect_flag.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/get_server_watch_paths.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/get_server_watch_paths.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/index.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/log.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/log_adapter.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/optimizer.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/optimizer.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/should_redirect_from_old_base_path.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/should_redirect_from_old_base_path.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/test_helpers.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/using_server_process.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/watcher.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/watcher.ts (100%) create mode 100644 packages/kbn-cli-dev-mode/tsconfig.json diff --git a/package.json b/package.json index ca2bc6907cb72f..9422583f57b7ea 100644 --- a/package.json +++ b/package.json @@ -360,6 +360,7 @@ "@jest/reporters": "^26.5.2", "@kbn/babel-code-parser": "link:packages/kbn-babel-code-parser", "@kbn/babel-preset": "link:packages/kbn-babel-preset", + "@kbn/cli-dev-mode": "link:packages/kbn-cli-dev-mode", "@kbn/dev-utils": "link:packages/kbn-dev-utils", "@kbn/docs-utils": "link:packages/kbn-docs-utils", "@kbn/es": "link:packages/kbn-es", diff --git a/src/dev/cli_dev_mode/README.md b/packages/kbn-cli-dev-mode/README.md similarity index 72% rename from src/dev/cli_dev_mode/README.md rename to packages/kbn-cli-dev-mode/README.md index 397017027a52f1..6ce41249674ce2 100644 --- a/src/dev/cli_dev_mode/README.md +++ b/packages/kbn-cli-dev-mode/README.md @@ -26,8 +26,12 @@ The `DevServer` object is responsible for everything related to running and rest The `Optimizer` object manages a `@kbn/optimizer` instance, adapting its configuration and logging to the data available to the CLI. -## `BasePathProxyServer` (currently passed from core) +## `BasePathProxyServer` -The `BasePathProxyServer` is passed to the `CliDevMode` from core when the dev mode is trigged by the `--dev` flag. This proxy injects a random three character base path in the URL that Kibana is served from to help ensure that Kibana features are written to adapt to custom base path configurations from users. +This proxy injects a random three character base path in the URL that Kibana is served from to help ensure that Kibana features +are written to adapt to custom base path configurations from users. -The basePathProxy also has another important job, ensuring that requests don't fail because the server is restarting and that the browser receives front-end assets containing all saved changes. We accomplish this by observing the ready state of the `Optimizer` and `DevServer` objects and pausing all requests through the proxy until both objects report that they aren't building/restarting based on recently saved changes. \ No newline at end of file +The basePathProxy also has another important job, ensuring that requests don't fail because the server is restarting and +that the browser receives front-end assets containing all saved changes. We accomplish this by observing the ready state of +the `Optimizer` and `DevServer` objects and pausing all requests through the proxy until both objects report that +they aren't building/restarting based on recently saved changes. \ No newline at end of file diff --git a/packages/kbn-cli-dev-mode/jest.config.js b/packages/kbn-cli-dev-mode/jest.config.js new file mode 100644 index 00000000000000..d04dc571ef2a0b --- /dev/null +++ b/packages/kbn-cli-dev-mode/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-cli-dev-mode'], +}; diff --git a/packages/kbn-cli-dev-mode/package.json b/packages/kbn-cli-dev-mode/package.json new file mode 100644 index 00000000000000..66809240f03ec4 --- /dev/null +++ b/packages/kbn-cli-dev-mode/package.json @@ -0,0 +1,25 @@ +{ + "name": "@kbn/cli-dev-mode", + "main": "./target/index.js", + "types": "./target/index.d.ts", + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "private": true, + "scripts": { + "build": "../../node_modules/.bin/tsc", + "kbn:bootstrap": "yarn build" + }, + "dependencies": { + "@kbn/config": "link:../kbn-config", + "@kbn/config-schema": "link:../kbn-config-schema", + "@kbn/logging": "link:../kbn-logging", + "@kbn/http-tools": "link:../kbn-http-tools", + "@kbn/optimizer": "link:../kbn-optimizer", + "@kbn/std": "link:../kbn-std", + "@kbn/utils": "link:../kbn-utils" + }, + "devDependencies": { + "@kbn/dev-utils": "link:../kbn-dev-utils", + "@kbn/utility-types": "link:../kbn-utility-types" + } +} \ No newline at end of file diff --git a/src/dev/cli_dev_mode/base_path_proxy_server.test.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts similarity index 100% rename from src/dev/cli_dev_mode/base_path_proxy_server.test.ts rename to packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts diff --git a/src/dev/cli_dev_mode/base_path_proxy_server.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts similarity index 100% rename from src/dev/cli_dev_mode/base_path_proxy_server.ts rename to packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts diff --git a/src/dev/cli_dev_mode/bootstrap.ts b/packages/kbn-cli-dev-mode/src/bootstrap.ts similarity index 100% rename from src/dev/cli_dev_mode/bootstrap.ts rename to packages/kbn-cli-dev-mode/src/bootstrap.ts diff --git a/src/dev/cli_dev_mode/cli_dev_mode.test.ts b/packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts similarity index 100% rename from src/dev/cli_dev_mode/cli_dev_mode.test.ts rename to packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts diff --git a/src/dev/cli_dev_mode/cli_dev_mode.ts b/packages/kbn-cli-dev-mode/src/cli_dev_mode.ts similarity index 100% rename from src/dev/cli_dev_mode/cli_dev_mode.ts rename to packages/kbn-cli-dev-mode/src/cli_dev_mode.ts diff --git a/src/dev/cli_dev_mode/config/dev_config.ts b/packages/kbn-cli-dev-mode/src/config/dev_config.ts similarity index 100% rename from src/dev/cli_dev_mode/config/dev_config.ts rename to packages/kbn-cli-dev-mode/src/config/dev_config.ts diff --git a/src/dev/cli_dev_mode/config/http_config.ts b/packages/kbn-cli-dev-mode/src/config/http_config.ts similarity index 100% rename from src/dev/cli_dev_mode/config/http_config.ts rename to packages/kbn-cli-dev-mode/src/config/http_config.ts diff --git a/src/dev/cli_dev_mode/config/index.ts b/packages/kbn-cli-dev-mode/src/config/index.ts similarity index 100% rename from src/dev/cli_dev_mode/config/index.ts rename to packages/kbn-cli-dev-mode/src/config/index.ts diff --git a/src/dev/cli_dev_mode/config/load_config.ts b/packages/kbn-cli-dev-mode/src/config/load_config.ts similarity index 100% rename from src/dev/cli_dev_mode/config/load_config.ts rename to packages/kbn-cli-dev-mode/src/config/load_config.ts diff --git a/src/dev/cli_dev_mode/config/plugins_config.ts b/packages/kbn-cli-dev-mode/src/config/plugins_config.ts similarity index 100% rename from src/dev/cli_dev_mode/config/plugins_config.ts rename to packages/kbn-cli-dev-mode/src/config/plugins_config.ts diff --git a/src/dev/cli_dev_mode/config/types.ts b/packages/kbn-cli-dev-mode/src/config/types.ts similarity index 100% rename from src/dev/cli_dev_mode/config/types.ts rename to packages/kbn-cli-dev-mode/src/config/types.ts diff --git a/src/dev/cli_dev_mode/dev_server.test.ts b/packages/kbn-cli-dev-mode/src/dev_server.test.ts similarity index 100% rename from src/dev/cli_dev_mode/dev_server.test.ts rename to packages/kbn-cli-dev-mode/src/dev_server.test.ts diff --git a/src/dev/cli_dev_mode/dev_server.ts b/packages/kbn-cli-dev-mode/src/dev_server.ts similarity index 100% rename from src/dev/cli_dev_mode/dev_server.ts rename to packages/kbn-cli-dev-mode/src/dev_server.ts diff --git a/src/dev/cli_dev_mode/get_active_inspect_flag.ts b/packages/kbn-cli-dev-mode/src/get_active_inspect_flag.ts similarity index 100% rename from src/dev/cli_dev_mode/get_active_inspect_flag.ts rename to packages/kbn-cli-dev-mode/src/get_active_inspect_flag.ts diff --git a/src/dev/cli_dev_mode/get_server_watch_paths.test.ts b/packages/kbn-cli-dev-mode/src/get_server_watch_paths.test.ts similarity index 100% rename from src/dev/cli_dev_mode/get_server_watch_paths.test.ts rename to packages/kbn-cli-dev-mode/src/get_server_watch_paths.test.ts diff --git a/src/dev/cli_dev_mode/get_server_watch_paths.ts b/packages/kbn-cli-dev-mode/src/get_server_watch_paths.ts similarity index 100% rename from src/dev/cli_dev_mode/get_server_watch_paths.ts rename to packages/kbn-cli-dev-mode/src/get_server_watch_paths.ts diff --git a/src/dev/cli_dev_mode/index.ts b/packages/kbn-cli-dev-mode/src/index.ts similarity index 100% rename from src/dev/cli_dev_mode/index.ts rename to packages/kbn-cli-dev-mode/src/index.ts diff --git a/src/dev/cli_dev_mode/log.ts b/packages/kbn-cli-dev-mode/src/log.ts similarity index 100% rename from src/dev/cli_dev_mode/log.ts rename to packages/kbn-cli-dev-mode/src/log.ts diff --git a/src/dev/cli_dev_mode/log_adapter.ts b/packages/kbn-cli-dev-mode/src/log_adapter.ts similarity index 100% rename from src/dev/cli_dev_mode/log_adapter.ts rename to packages/kbn-cli-dev-mode/src/log_adapter.ts diff --git a/src/dev/cli_dev_mode/optimizer.test.ts b/packages/kbn-cli-dev-mode/src/optimizer.test.ts similarity index 100% rename from src/dev/cli_dev_mode/optimizer.test.ts rename to packages/kbn-cli-dev-mode/src/optimizer.test.ts diff --git a/src/dev/cli_dev_mode/optimizer.ts b/packages/kbn-cli-dev-mode/src/optimizer.ts similarity index 100% rename from src/dev/cli_dev_mode/optimizer.ts rename to packages/kbn-cli-dev-mode/src/optimizer.ts diff --git a/src/dev/cli_dev_mode/should_redirect_from_old_base_path.test.ts b/packages/kbn-cli-dev-mode/src/should_redirect_from_old_base_path.test.ts similarity index 100% rename from src/dev/cli_dev_mode/should_redirect_from_old_base_path.test.ts rename to packages/kbn-cli-dev-mode/src/should_redirect_from_old_base_path.test.ts diff --git a/src/dev/cli_dev_mode/should_redirect_from_old_base_path.ts b/packages/kbn-cli-dev-mode/src/should_redirect_from_old_base_path.ts similarity index 100% rename from src/dev/cli_dev_mode/should_redirect_from_old_base_path.ts rename to packages/kbn-cli-dev-mode/src/should_redirect_from_old_base_path.ts diff --git a/src/dev/cli_dev_mode/test_helpers.ts b/packages/kbn-cli-dev-mode/src/test_helpers.ts similarity index 100% rename from src/dev/cli_dev_mode/test_helpers.ts rename to packages/kbn-cli-dev-mode/src/test_helpers.ts diff --git a/src/dev/cli_dev_mode/using_server_process.ts b/packages/kbn-cli-dev-mode/src/using_server_process.ts similarity index 100% rename from src/dev/cli_dev_mode/using_server_process.ts rename to packages/kbn-cli-dev-mode/src/using_server_process.ts diff --git a/src/dev/cli_dev_mode/watcher.test.ts b/packages/kbn-cli-dev-mode/src/watcher.test.ts similarity index 100% rename from src/dev/cli_dev_mode/watcher.test.ts rename to packages/kbn-cli-dev-mode/src/watcher.test.ts diff --git a/src/dev/cli_dev_mode/watcher.ts b/packages/kbn-cli-dev-mode/src/watcher.ts similarity index 100% rename from src/dev/cli_dev_mode/watcher.ts rename to packages/kbn-cli-dev-mode/src/watcher.ts diff --git a/packages/kbn-cli-dev-mode/tsconfig.json b/packages/kbn-cli-dev-mode/tsconfig.json new file mode 100644 index 00000000000000..ba00ddfa6adb6f --- /dev/null +++ b/packages/kbn-cli-dev-mode/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "declaration": true, + "outDir": "./target", + "stripInternal": false, + "declarationMap": true, + "types": ["jest", "node"] + }, + "include": ["./src/**/*.ts"], + "exclude": ["target"] +} diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 4f77aa687a690e..f8bc46f06c6b93 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -31,12 +31,11 @@ function canRequire(path) { } } -const DEV_MODE_PATH = resolve(__dirname, '../../dev/cli_dev_mode'); -const DEV_MODE_SUPPORTED = canRequire(DEV_MODE_PATH); +const DEV_MODE_SUPPORTED = canRequire('@kbn/cli-dev-mode'); const getBootstrapScript = (isDev) => { if (DEV_MODE_SUPPORTED && isDev && process.env.isDevCliChild !== 'true') { - const { bootstrapDevMode } = require('../../dev/cli_dev_mode'); + const { bootstrapDevMode } = require('@kbn/cli-dev-mode'); return bootstrapDevMode; } else { const { bootstrap } = require('../../core/server'); diff --git a/yarn.lock b/yarn.lock index dac5d16d61ac27..58bdb20e925cab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2617,6 +2617,10 @@ version "0.0.0" uid "" +"@kbn/cli-dev-mode@link:packages/kbn-cli-dev-mode": + version "0.0.0" + uid "" + "@kbn/config-schema@link:packages/kbn-config-schema": version "0.0.0" uid "" From 6908053c6677022a17569fa040b1c925390032ab Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 25 Mar 2021 09:19:06 +0100 Subject: [PATCH 20/38] remove useless comment --- packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts index 3554bc2982757e..3a12a6c749a493 100644 --- a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts @@ -16,11 +16,6 @@ import { BasePathProxyServer, BasePathProxyServerOptions } from './base_path_pro import { DevConfig } from './config/dev_config'; import { TestLog } from './log'; -/** - * Most of these tests are inspired by: - * src/core/server/http/http_server.test.ts - * and copied for completeness from that file. The modifications are that these tests use the developer proxy. - */ describe('BasePathProxyServer', () => { let server: Server; let proxyServer: BasePathProxyServer; From 587d2753ac6f187c6f9db14dbd505a3015c5984e Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 25 Mar 2021 10:33:50 +0100 Subject: [PATCH 21/38] self-review NITS --- packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts | 2 +- src/core/server/bootstrap.ts | 1 - src/core/server/root/index.ts | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts b/packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts index b8d299e37ced7f..d5bafe7280bd92 100644 --- a/packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts +++ b/packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts @@ -176,7 +176,7 @@ it('disables the watcher', () => { expect(Watcher.mock.calls[0][0]).toHaveProperty('enabled', false); }); -it('enable the basePath proxy', () => { +it('enables the basePath proxy', () => { new CliDevMode(createOptions({ cliArgs: { basePath: true } })); expect(BasePathProxyServer).toHaveBeenCalledTimes(1); diff --git a/src/core/server/bootstrap.ts b/src/core/server/bootstrap.ts index e62671e6c5ec39..4a07e0c010685a 100644 --- a/src/core/server/bootstrap.ts +++ b/src/core/server/bootstrap.ts @@ -24,7 +24,6 @@ interface BootstrapArgs { */ export async function bootstrap({ configs, cliArgs, applyConfigOverrides }: BootstrapArgs) { if (cliArgs.optimize) { - // TODO: move to devCliMode // --optimize is deprecated and does nothing now, avoid starting up and just shutdown return; } diff --git a/src/core/server/root/index.ts b/src/core/server/root/index.ts index b1750483308e98..c6ed4fbcb9f049 100644 --- a/src/core/server/root/index.ts +++ b/src/core/server/root/index.ts @@ -87,7 +87,6 @@ export class Root { // Stream that maps config updates to logger updates, including update failures. const update$ = configService.getConfig$().pipe( // always read the logging config when the underlying config object is re-read - // except for the CLI process where we only apply the default logging config once switchMap(() => configService.atPath('logging')), concatMap((config) => this.loggingSystem.upgrade(config)), // This specifically console.logs because we were not able to configure the logger. From 3092af12f617f2ca131b277fb48f5d5ab48e1e20 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 25 Mar 2021 10:35:11 +0100 Subject: [PATCH 22/38] update CODEOWNERS file --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2f2f260addb35e..1d063d4dedd82b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -157,6 +157,7 @@ /packages/kbn-ui-shared-deps/ @elastic/kibana-operations /packages/kbn-es-archiver/ @elastic/kibana-operations /packages/kbn-utils/ @elastic/kibana-operations +/packages/kbn-cli-dev-mode/ @elastic/kibana-operations /src/cli/keystore/ @elastic/kibana-operations /src/legacy/server/warnings/ @elastic/kibana-operations /.ci/es-snapshots/ @elastic/kibana-operations @@ -193,6 +194,8 @@ /packages/kbn-config/ @elastic/kibana-core /packages/kbn-logging/ @elastic/kibana-core /packages/kbn-legacy-logging/ @elastic/kibana-core +/packages/kbn-crypto/ @elastic/kibana-core +/packages/kbn-http-tools/ @elastic/kibana-core /src/legacy/server/config/ @elastic/kibana-core /src/legacy/server/http/ @elastic/kibana-core /src/legacy/server/logging/ @elastic/kibana-core From 74a7a35057d031ec8e2d37076a6e493cc23935df Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 25 Mar 2021 12:23:24 +0100 Subject: [PATCH 23/38] add devOnly flag --- packages/kbn-cli-dev-mode/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/kbn-cli-dev-mode/package.json b/packages/kbn-cli-dev-mode/package.json index 66809240f03ec4..e4160320cfcb5d 100644 --- a/packages/kbn-cli-dev-mode/package.json +++ b/packages/kbn-cli-dev-mode/package.json @@ -9,6 +9,9 @@ "build": "../../node_modules/.bin/tsc", "kbn:bootstrap": "yarn build" }, + "kibana": { + "devOnly": true + }, "dependencies": { "@kbn/config": "link:../kbn-config", "@kbn/config-schema": "link:../kbn-config-schema", From 35420c65747fc9d6327c368b6adb41a7c16cbcf6 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 25 Mar 2021 15:25:00 +0100 Subject: [PATCH 24/38] use variable for DEV_MODE_PATH --- src/cli/serve/serve.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index f8bc46f06c6b93..7ce4e02f320788 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -31,11 +31,14 @@ function canRequire(path) { } } -const DEV_MODE_SUPPORTED = canRequire('@kbn/cli-dev-mode'); +const DEV_MODE_PATH = '@kbn/cli-dev-mode'; +const DEV_MODE_SUPPORTED = canRequire(DEV_MODE_PATH); const getBootstrapScript = (isDev) => { if (DEV_MODE_SUPPORTED && isDev && process.env.isDevCliChild !== 'true') { - const { bootstrapDevMode } = require('@kbn/cli-dev-mode'); + // need dynamic require to exclude it from production build + // eslint-disable-next-line import/no-dynamic-require + const { bootstrapDevMode } = require(DEV_MODE_PATH); return bootstrapDevMode; } else { const { bootstrap } = require('../../core/server'); From eafa84c4494680fd0e124a6170f62f6132480f27 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 26 Mar 2021 08:46:36 +0100 Subject: [PATCH 25/38] review comments --- packages/kbn-http-tools/src/get_server_options.test.ts | 2 +- packages/kbn-http-tools/src/get_server_options.ts | 2 +- packages/kbn-http-tools/src/ssl/ssl_config.ts | 2 +- packages/kbn-http-tools/src/types.ts | 2 +- src/core/server/elasticsearch/elasticsearch_config.test.ts | 6 +++--- src/core/server/http/http_server.test.ts | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/kbn-http-tools/src/get_server_options.test.ts b/packages/kbn-http-tools/src/get_server_options.test.ts index 03fe9268a8db7b..fdcc749f4ae9a1 100644 --- a/packages/kbn-http-tools/src/get_server_options.test.ts +++ b/packages/kbn-http-tools/src/get_server_options.test.ts @@ -82,7 +82,7 @@ describe('getServerOptions', () => { keyPassphrase: 'passPhrase', rejectUnauthorized: true, requestCert: true, - secureOptions: 42, + getSecureOptions: () => 42, }, }); diff --git a/packages/kbn-http-tools/src/get_server_options.ts b/packages/kbn-http-tools/src/get_server_options.ts index 25715f636e3fcc..047890b7ce8c4b 100644 --- a/packages/kbn-http-tools/src/get_server_options.ts +++ b/packages/kbn-http-tools/src/get_server_options.ts @@ -73,7 +73,7 @@ export function getServerOptions(config: IHttpConfig, { configureTLS = true } = honorCipherOrder: true, key: ssl.key, passphrase: ssl.keyPassphrase, - secureOptions: ssl.secureOptions, + secureOptions: ssl.getSecureOptions ? ssl.getSecureOptions() : undefined, requestCert: ssl.requestCert, rejectUnauthorized: ssl.rejectUnauthorized, }; diff --git a/packages/kbn-http-tools/src/ssl/ssl_config.ts b/packages/kbn-http-tools/src/ssl/ssl_config.ts index 8da0e5145d0dc8..53d3616a09a75e 100644 --- a/packages/kbn-http-tools/src/ssl/ssl_config.ts +++ b/packages/kbn-http-tools/src/ssl/ssl_config.ts @@ -145,7 +145,7 @@ export class SslConfig { /** * Options that affect the OpenSSL protocol behavior via numeric bitmask of the SSL_OP_* options from OpenSSL Options. */ - public get secureOptions() { + public getSecureOptions() { // our validation should ensure that this.supportedProtocols is at least an empty array, // which the following logic depends upon. if (this.supportedProtocols == null || this.supportedProtocols.length === 0) { diff --git a/packages/kbn-http-tools/src/types.ts b/packages/kbn-http-tools/src/types.ts index 97a1c595820e55..3cc117d542eeec 100644 --- a/packages/kbn-http-tools/src/types.ts +++ b/packages/kbn-http-tools/src/types.ts @@ -33,5 +33,5 @@ export interface ISslConfig { keyPassphrase?: string; requestCert?: boolean; rejectUnauthorized?: boolean; - secureOptions?: number; + getSecureOptions?: () => number; } diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.ts b/src/core/server/elasticsearch/elasticsearch_config.test.ts index 0efe12df981feb..4b6cf220ccd525 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.test.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.test.ts @@ -244,12 +244,12 @@ describe('throws when config is invalid', () => { beforeAll(() => { const realFs = jest.requireActual('fs'); mockReadFileSync.mockImplementation((path: string) => realFs.readFileSync(path)); - const utils = jest.requireActual('@kbn/crypto'); + const crypto = jest.requireActual('@kbn/crypto'); mockReadPkcs12Keystore.mockImplementation((path: string, password?: string) => - utils.readPkcs12Keystore(path, password) + crypto.readPkcs12Keystore(path, password) ); mockReadPkcs12Truststore.mockImplementation((path: string, password?: string) => - utils.readPkcs12Truststore(path, password) + crypto.readPkcs12Truststore(path, password) ); }); diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index 6a7dd44a292fb3..54be7b35f68ad4 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -73,7 +73,7 @@ beforeEach(() => { enabled: true, certificate, cipherSuites: ['TLS_AES_256_GCM_SHA384'], - secureOptions: 0, + getSecureOptions: () => 0, key, redirectHttpFromPort: config.port + 1, }, From 83943d10107cf5809338b4323f96f9345b66f97f Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 26 Mar 2021 13:33:02 +0100 Subject: [PATCH 26/38] fix logger/log adapter --- packages/kbn-cli-dev-mode/src/log_adapter.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/kbn-cli-dev-mode/src/log_adapter.ts b/packages/kbn-cli-dev-mode/src/log_adapter.ts index c334afcb32464d..aa1429c0ed846d 100644 --- a/packages/kbn-cli-dev-mode/src/log_adapter.ts +++ b/packages/kbn-cli-dev-mode/src/log_adapter.ts @@ -22,13 +22,13 @@ export const convertToLogger = (cliLog: Log): Logger => { }; const adapter: Logger = { - trace: (message) => cliLog.good(message), - debug: (message) => cliLog.good(message), - info: (message) => cliLog.good(message), - warn: (msgOrError) => cliLog.warn(getErrorMessage(msgOrError)), - error: (msgOrError) => cliLog.bad(getErrorMessage(msgOrError)), - fatal: (msgOrError) => cliLog.bad(getErrorMessage(msgOrError)), - log: (record) => cliLog.good(record.message), + trace: (message) => cliLog.write(message), + debug: (message) => cliLog.write(message), + info: (message) => cliLog.write(message), + warn: (msgOrError) => cliLog.warn('warning', getErrorMessage(msgOrError)), + error: (msgOrError) => cliLog.bad('error', getErrorMessage(msgOrError)), + fatal: (msgOrError) => cliLog.bad('fatal', getErrorMessage(msgOrError)), + log: (record) => cliLog.write(record.message), get: () => adapter, }; return adapter; From bd2a5a87a196fbe28e5cb6513a53a3c9e450633c Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 26 Mar 2021 13:34:54 +0100 Subject: [PATCH 27/38] fix log calls in base path proxy server --- packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts index 8d2c03762f4b99..21ed6ee8298345 100644 --- a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts @@ -63,7 +63,7 @@ export class BasePathProxyServer { } public async start(options: BasePathProxyServerOptions) { - this.log.good('starting basepath proxy server'); + this.log.write('starting basepath proxy server'); const serverOptions = getServerOptions(this.httpConfig); const listenerOptions = getListenerOptions(this.httpConfig); @@ -88,7 +88,7 @@ export class BasePathProxyServer { await this.server.start(); - this.log.good( + this.log.write( `basepath proxy server running at ${Url.format({ host: this.server.info.uri, pathname: this.httpConfig.basePath, @@ -101,7 +101,7 @@ export class BasePathProxyServer { return; } - this.log.good('stopping basepath proxy server'); + this.log.write('stopping basepath proxy server'); await this.server.stop(); this.server = undefined; From b14bdccfe83c87449c21899285e1803054fb558c Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 29 Mar 2021 10:19:11 +0200 Subject: [PATCH 28/38] address some review comments --- packages/kbn-crypto/README.md | 3 +++ packages/kbn-crypto/tsconfig.json | 1 - packages/kbn-http-tools/src/get_request_id.test.ts | 2 +- packages/kbn-http-tools/src/get_request_id.ts | 8 ++++---- packages/kbn-http-tools/src/get_server_options.ts | 10 ---------- 5 files changed, 8 insertions(+), 16 deletions(-) create mode 100644 packages/kbn-crypto/README.md diff --git a/packages/kbn-crypto/README.md b/packages/kbn-crypto/README.md new file mode 100644 index 00000000000000..4404c22eba37c5 --- /dev/null +++ b/packages/kbn-crypto/README.md @@ -0,0 +1,3 @@ +# @kbn/crypto + +Crypto tools and utilities for Kibana \ No newline at end of file diff --git a/packages/kbn-crypto/tsconfig.json b/packages/kbn-crypto/tsconfig.json index 1c6c671d0b7683..e9dd6313e6f79e 100644 --- a/packages/kbn-crypto/tsconfig.json +++ b/packages/kbn-crypto/tsconfig.json @@ -2,7 +2,6 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "target", - "target": "ES2019", "declaration": true, "declarationMap": true }, diff --git a/packages/kbn-http-tools/src/get_request_id.test.ts b/packages/kbn-http-tools/src/get_request_id.test.ts index d0dc8a0085c9a8..1b098ed4842d30 100644 --- a/packages/kbn-http-tools/src/get_request_id.test.ts +++ b/packages/kbn-http-tools/src/get_request_id.test.ts @@ -28,8 +28,8 @@ describe('getRequestId', () => { const request = { headers: { 'x-opaque-id': 'id from header', - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, }, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, } as any; expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( 'id from header' diff --git a/packages/kbn-http-tools/src/get_request_id.ts b/packages/kbn-http-tools/src/get_request_id.ts index 42ae56568b30a5..3af70ecc3a7a32 100644 --- a/packages/kbn-http-tools/src/get_request_id.ts +++ b/packages/kbn-http-tools/src/get_request_id.ts @@ -11,12 +11,12 @@ import uuid from 'uuid'; export function getRequestId( request: Request, - options: { allowFromAnyIp: boolean; ipAllowlist: string[] } + { allowFromAnyIp, ipAllowlist }: { allowFromAnyIp: boolean; ipAllowlist: string[] } ): string { - return options.allowFromAnyIp || + const remoteAddress = request.raw.req.socket?.remoteAddress; + return allowFromAnyIp || // socket may be undefined in integration tests that connect via the http listener directly - (request.raw.req.socket?.remoteAddress && - options.ipAllowlist.includes(request.raw.req.socket.remoteAddress)) + (remoteAddress && ipAllowlist.includes(remoteAddress)) ? request.headers['x-opaque-id'] ?? uuid.v4() : uuid.v4(); } diff --git a/packages/kbn-http-tools/src/get_server_options.ts b/packages/kbn-http-tools/src/get_server_options.ts index 047890b7ce8c4b..ade90a0e0d3f5d 100644 --- a/packages/kbn-http-tools/src/get_server_options.ts +++ b/packages/kbn-http-tools/src/get_server_options.ts @@ -7,7 +7,6 @@ */ import { RouteOptionsCors, ServerOptions } from '@hapi/hapi'; -import { ensureNoUnsafeProperties } from '@kbn/std'; import { ServerOptions as TLSOptions } from 'https'; import { defaultValidationErrorHandler } from './default_validation_error_handler'; import { IHttpConfig } from './types'; @@ -25,10 +24,6 @@ export function getServerOptions(config: IHttpConfig, { configureTLS = true } = headers: corsAllowedHeaders, } : false; - // Note that all connection options configured here should be exactly the same - // as in the legacy platform server (see `src/legacy/server/http/index`). Any change - // SHOULD BE applied in both places. The only exception is TLS-specific options, - // that are configured only here. const options: ServerOptions = { host: config.host, port: config.port, @@ -46,11 +41,6 @@ export function getServerOptions(config: IHttpConfig, { configureTLS = true } = options: { abortEarly: false, }, - // TODO: This payload validation can be removed once the legacy platform is completely removed. - // This is a default payload validation which applies to all LP routes which do not specify their own - // `validate.payload` handler, in order to reduce the likelyhood of prototype pollution vulnerabilities. - // (All NP routes are already required to specify their own validation in order to access the payload) - payload: (value) => Promise.resolve(ensureNoUnsafeProperties(value)), }, }, state: { From 78d0d42354e9c77166726ea643539016ebbe16d8 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 29 Mar 2021 10:23:50 +0200 Subject: [PATCH 29/38] rename @kbn/http-tools to @kbn/server-http-tools --- package.json | 2 +- packages/kbn-cli-dev-mode/package.json | 2 +- .../kbn-cli-dev-mode/src/base_path_proxy_server.test.ts | 2 +- packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts | 2 +- packages/kbn-cli-dev-mode/src/config/http_config.ts | 2 +- .../{kbn-http-tools => kbn-server-http-tools}/README.md | 0 .../jest.config.js | 2 +- .../{kbn-http-tools => kbn-server-http-tools}/package.json | 2 +- .../src/create_server.ts | 0 .../src/default_validation_error_handler.test.ts | 0 .../src/default_validation_error_handler.ts | 0 .../src/get_listener_options.ts | 0 .../src/get_request_id.test.ts | 0 .../src/get_request_id.ts | 0 .../src/get_server_options.test.ts | 0 .../src/get_server_options.ts | 0 .../{kbn-http-tools => kbn-server-http-tools}/src/index.ts | 0 .../src/ssl/index.ts | 0 .../src/ssl/ssl_config.test.mocks.ts | 0 .../src/ssl/ssl_config.test.ts | 0 .../src/ssl/ssl_config.ts | 0 .../{kbn-http-tools => kbn-server-http-tools}/src/types.ts | 0 .../{kbn-http-tools => kbn-server-http-tools}/tsconfig.json | 0 src/core/server/http/http_config.ts | 2 +- src/core/server/http/http_server.ts | 2 +- src/core/server/http/https_redirect_server.ts | 2 +- yarn.lock | 6 +++++- 27 files changed, 15 insertions(+), 11 deletions(-) rename packages/{kbn-http-tools => kbn-server-http-tools}/README.md (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/jest.config.js (88%) rename packages/{kbn-http-tools => kbn-server-http-tools}/package.json (93%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/create_server.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/default_validation_error_handler.test.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/default_validation_error_handler.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/get_listener_options.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/get_request_id.test.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/get_request_id.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/get_server_options.test.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/get_server_options.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/index.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/ssl/index.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/ssl/ssl_config.test.mocks.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/ssl/ssl_config.test.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/ssl/ssl_config.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/src/types.ts (100%) rename packages/{kbn-http-tools => kbn-server-http-tools}/tsconfig.json (100%) diff --git a/package.json b/package.json index cdf87058a18cdf..db7447fb1aa63d 100644 --- a/package.json +++ b/package.json @@ -128,12 +128,12 @@ "@kbn/config": "link:packages/kbn-config", "@kbn/config-schema": "link:packages/kbn-config-schema", "@kbn/crypto": "link:packages/kbn-crypto", - "@kbn/http-tools": "link:packages/kbn-http-tools", "@kbn/i18n": "link:packages/kbn-i18n", "@kbn/interpreter": "link:packages/kbn-interpreter", "@kbn/legacy-logging": "link:packages/kbn-legacy-logging", "@kbn/logging": "link:packages/kbn-logging", "@kbn/monaco": "link:packages/kbn-monaco", + "@kbn/server-http-tools": "link:packages/kbn-server-http-tools", "@kbn/std": "link:packages/kbn-std", "@kbn/tinymath": "link:packages/kbn-tinymath", "@kbn/ui-framework": "link:packages/kbn-ui-framework", diff --git a/packages/kbn-cli-dev-mode/package.json b/packages/kbn-cli-dev-mode/package.json index e4160320cfcb5d..0fe711145415b0 100644 --- a/packages/kbn-cli-dev-mode/package.json +++ b/packages/kbn-cli-dev-mode/package.json @@ -16,7 +16,7 @@ "@kbn/config": "link:../kbn-config", "@kbn/config-schema": "link:../kbn-config-schema", "@kbn/logging": "link:../kbn-logging", - "@kbn/http-tools": "link:../kbn-http-tools", + "@kbn/http-tools": "link:../kbn-server-http-tools", "@kbn/optimizer": "link:../kbn-optimizer", "@kbn/std": "link:../kbn-std", "@kbn/utils": "link:../kbn-utils" diff --git a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts index 3a12a6c749a493..11637a0b41ff48 100644 --- a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts @@ -9,7 +9,7 @@ import { Server } from '@hapi/hapi'; import { EMPTY } from 'rxjs'; import supertest from 'supertest'; -import { getServerOptions, getListenerOptions, createServer, IHttpConfig } from '@kbn/http-tools'; +import { getServerOptions, getListenerOptions, createServer, IHttpConfig } from '@kbn/server-http-tools'; import { ByteSizeValue } from '@kbn/config-schema'; import { BasePathProxyServer, BasePathProxyServerOptions } from './base_path_proxy_server'; diff --git a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts index 21ed6ee8298345..40841c8327cc29 100644 --- a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts @@ -15,7 +15,7 @@ import { sampleSize } from 'lodash'; import * as Rx from 'rxjs'; import { take } from 'rxjs/operators'; import { ByteSizeValue } from '@kbn/config-schema'; -import { createServer, getListenerOptions, getServerOptions } from '@kbn/http-tools'; +import { createServer, getListenerOptions, getServerOptions } from '@kbn/server-http-tools'; import { DevConfig, HttpConfig } from './config'; import { Log } from './log'; diff --git a/packages/kbn-cli-dev-mode/src/config/http_config.ts b/packages/kbn-cli-dev-mode/src/config/http_config.ts index 36a3009d27dbe4..34f208c28df680 100644 --- a/packages/kbn-cli-dev-mode/src/config/http_config.ts +++ b/packages/kbn-cli-dev-mode/src/config/http_config.ts @@ -7,7 +7,7 @@ */ import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema'; -import { ICorsConfig, IHttpConfig, ISslConfig, SslConfig, sslSchema } from '@kbn/http-tools'; +import { ICorsConfig, IHttpConfig, ISslConfig, SslConfig, sslSchema } from '@kbn/server-http-tools'; export const httpConfigSchema = schema.object( { diff --git a/packages/kbn-http-tools/README.md b/packages/kbn-server-http-tools/README.md similarity index 100% rename from packages/kbn-http-tools/README.md rename to packages/kbn-server-http-tools/README.md diff --git a/packages/kbn-http-tools/jest.config.js b/packages/kbn-server-http-tools/jest.config.js similarity index 88% rename from packages/kbn-http-tools/jest.config.js rename to packages/kbn-server-http-tools/jest.config.js index b0b4cf8897804d..e409c235546227 100644 --- a/packages/kbn-http-tools/jest.config.js +++ b/packages/kbn-server-http-tools/jest.config.js @@ -9,5 +9,5 @@ module.exports = { preset: '@kbn/test', rootDir: '../..', - roots: ['/packages/kbn-http-tools'], + roots: ['/packages/kbn-server-http-tools'], }; diff --git a/packages/kbn-http-tools/package.json b/packages/kbn-server-http-tools/package.json similarity index 93% rename from packages/kbn-http-tools/package.json rename to packages/kbn-server-http-tools/package.json index 12d3a2119b88cc..a8f99689f33354 100644 --- a/packages/kbn-http-tools/package.json +++ b/packages/kbn-server-http-tools/package.json @@ -1,5 +1,5 @@ { - "name": "@kbn/http-tools", + "name": "@kbn/server-http-tools", "main": "./target/index.js", "version": "1.0.0", "license": "SSPL-1.0 OR Elastic License 2.0", diff --git a/packages/kbn-http-tools/src/create_server.ts b/packages/kbn-server-http-tools/src/create_server.ts similarity index 100% rename from packages/kbn-http-tools/src/create_server.ts rename to packages/kbn-server-http-tools/src/create_server.ts diff --git a/packages/kbn-http-tools/src/default_validation_error_handler.test.ts b/packages/kbn-server-http-tools/src/default_validation_error_handler.test.ts similarity index 100% rename from packages/kbn-http-tools/src/default_validation_error_handler.test.ts rename to packages/kbn-server-http-tools/src/default_validation_error_handler.test.ts diff --git a/packages/kbn-http-tools/src/default_validation_error_handler.ts b/packages/kbn-server-http-tools/src/default_validation_error_handler.ts similarity index 100% rename from packages/kbn-http-tools/src/default_validation_error_handler.ts rename to packages/kbn-server-http-tools/src/default_validation_error_handler.ts diff --git a/packages/kbn-http-tools/src/get_listener_options.ts b/packages/kbn-server-http-tools/src/get_listener_options.ts similarity index 100% rename from packages/kbn-http-tools/src/get_listener_options.ts rename to packages/kbn-server-http-tools/src/get_listener_options.ts diff --git a/packages/kbn-http-tools/src/get_request_id.test.ts b/packages/kbn-server-http-tools/src/get_request_id.test.ts similarity index 100% rename from packages/kbn-http-tools/src/get_request_id.test.ts rename to packages/kbn-server-http-tools/src/get_request_id.test.ts diff --git a/packages/kbn-http-tools/src/get_request_id.ts b/packages/kbn-server-http-tools/src/get_request_id.ts similarity index 100% rename from packages/kbn-http-tools/src/get_request_id.ts rename to packages/kbn-server-http-tools/src/get_request_id.ts diff --git a/packages/kbn-http-tools/src/get_server_options.test.ts b/packages/kbn-server-http-tools/src/get_server_options.test.ts similarity index 100% rename from packages/kbn-http-tools/src/get_server_options.test.ts rename to packages/kbn-server-http-tools/src/get_server_options.test.ts diff --git a/packages/kbn-http-tools/src/get_server_options.ts b/packages/kbn-server-http-tools/src/get_server_options.ts similarity index 100% rename from packages/kbn-http-tools/src/get_server_options.ts rename to packages/kbn-server-http-tools/src/get_server_options.ts diff --git a/packages/kbn-http-tools/src/index.ts b/packages/kbn-server-http-tools/src/index.ts similarity index 100% rename from packages/kbn-http-tools/src/index.ts rename to packages/kbn-server-http-tools/src/index.ts diff --git a/packages/kbn-http-tools/src/ssl/index.ts b/packages/kbn-server-http-tools/src/ssl/index.ts similarity index 100% rename from packages/kbn-http-tools/src/ssl/index.ts rename to packages/kbn-server-http-tools/src/ssl/index.ts diff --git a/packages/kbn-http-tools/src/ssl/ssl_config.test.mocks.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.mocks.ts similarity index 100% rename from packages/kbn-http-tools/src/ssl/ssl_config.test.mocks.ts rename to packages/kbn-server-http-tools/src/ssl/ssl_config.test.mocks.ts diff --git a/packages/kbn-http-tools/src/ssl/ssl_config.test.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts similarity index 100% rename from packages/kbn-http-tools/src/ssl/ssl_config.test.ts rename to packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts diff --git a/packages/kbn-http-tools/src/ssl/ssl_config.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.ts similarity index 100% rename from packages/kbn-http-tools/src/ssl/ssl_config.ts rename to packages/kbn-server-http-tools/src/ssl/ssl_config.ts diff --git a/packages/kbn-http-tools/src/types.ts b/packages/kbn-server-http-tools/src/types.ts similarity index 100% rename from packages/kbn-http-tools/src/types.ts rename to packages/kbn-server-http-tools/src/types.ts diff --git a/packages/kbn-http-tools/tsconfig.json b/packages/kbn-server-http-tools/tsconfig.json similarity index 100% rename from packages/kbn-http-tools/tsconfig.json rename to packages/kbn-server-http-tools/tsconfig.json diff --git a/src/core/server/http/http_config.ts b/src/core/server/http/http_config.ts index 47e9e84e550ece..356dad201ce95d 100644 --- a/src/core/server/http/http_config.ts +++ b/src/core/server/http/http_config.ts @@ -7,7 +7,7 @@ */ import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema'; -import { IHttpConfig, SslConfig, sslSchema } from '@kbn/http-tools'; +import { IHttpConfig, SslConfig, sslSchema } from '@kbn/server-http-tools'; import { hostname } from 'os'; import url from 'url'; diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index a6dc92cf229b15..d02dc260be0612 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -10,7 +10,7 @@ import { Server, Request } from '@hapi/hapi'; import HapiStaticFiles from '@hapi/inert'; import url from 'url'; import uuid from 'uuid'; -import { createServer, getListenerOptions, getServerOptions, getRequestId } from '@kbn/http-tools'; +import { createServer, getListenerOptions, getServerOptions, getRequestId } from '@kbn/server-http-tools'; import { Logger, LoggerFactory } from '../logging'; import { HttpConfig } from './http_config'; diff --git a/src/core/server/http/https_redirect_server.ts b/src/core/server/http/https_redirect_server.ts index 0eb5cedbc15929..28909c0308c223 100644 --- a/src/core/server/http/https_redirect_server.ts +++ b/src/core/server/http/https_redirect_server.ts @@ -8,7 +8,7 @@ import { Request, ResponseToolkit, Server } from '@hapi/hapi'; import { format as formatUrl } from 'url'; -import { createServer, getListenerOptions, getServerOptions } from '@kbn/http-tools'; +import { createServer, getListenerOptions, getServerOptions } from '@kbn/server-http-tools'; import { Logger } from '../logging'; import { HttpConfig } from './http_config'; diff --git a/yarn.lock b/yarn.lock index 7ddcd2d4f13ad1..ec7fb39b2bf1eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2662,7 +2662,7 @@ version "0.0.0" uid "" -"@kbn/http-tools@link:packages/kbn-http-tools": +"@kbn/http-tools@link:packages/kbn-server-http-tools": version "0.0.0" uid "" @@ -2702,6 +2702,10 @@ version "0.0.0" uid "" +"@kbn/server-http-tools@link:packages/kbn-server-http-tools": + version "0.0.0" + uid "" + "@kbn/std@link:packages/kbn-std": version "0.0.0" uid "" From 70dadaa1db5baee8c9f8ec986351c27c8cae99ef Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 29 Mar 2021 10:38:02 +0200 Subject: [PATCH 30/38] more review comments --- packages/kbn-cli-dev-mode/src/log_adapter.ts | 9 +-------- packages/kbn-cli-dev-mode/tsconfig.json | 1 - packages/kbn-utils/src/repo_root.ts | 2 ++ src/cli/serve/serve.js | 4 +--- src/core/server/http/http_service.ts | 8 +++----- src/core/server/plugins/plugins_service.ts | 5 ++--- 6 files changed, 9 insertions(+), 20 deletions(-) diff --git a/packages/kbn-cli-dev-mode/src/log_adapter.ts b/packages/kbn-cli-dev-mode/src/log_adapter.ts index aa1429c0ed846d..65161fcc56e0e6 100644 --- a/packages/kbn-cli-dev-mode/src/log_adapter.ts +++ b/packages/kbn-cli-dev-mode/src/log_adapter.ts @@ -6,16 +6,9 @@ * Side Public License, v 1. */ -import { LoggerFactory, Logger } from '@kbn/logging'; +import { Logger } from '@kbn/logging'; import { Log } from './log'; -export const convertToLoggerFactory = (cliLog: Log): LoggerFactory => { - const adapted = convertToLogger(cliLog); - return { - get: () => adapted, - }; -}; - export const convertToLogger = (cliLog: Log): Logger => { const getErrorMessage = (msgOrError: string | Error): string => { return typeof msgOrError === 'string' ? msgOrError : msgOrError.message; diff --git a/packages/kbn-cli-dev-mode/tsconfig.json b/packages/kbn-cli-dev-mode/tsconfig.json index ba00ddfa6adb6f..b2bdaf8ceea36e 100644 --- a/packages/kbn-cli-dev-mode/tsconfig.json +++ b/packages/kbn-cli-dev-mode/tsconfig.json @@ -3,7 +3,6 @@ "compilerOptions": { "declaration": true, "outDir": "./target", - "stripInternal": false, "declarationMap": true, "types": ["jest", "node"] }, diff --git a/packages/kbn-utils/src/repo_root.ts b/packages/kbn-utils/src/repo_root.ts index 20a25023f41660..2c1617098fe20f 100644 --- a/packages/kbn-utils/src/repo_root.ts +++ b/packages/kbn-utils/src/repo_root.ts @@ -57,3 +57,5 @@ const { kibanaDir, kibanaPkgJson } = findKibanaPackageJson(); export const REPO_ROOT = kibanaDir; export const UPSTREAM_BRANCH = kibanaPkgJson.branch; + +export const fromRoot = (...paths: string[]) => Path.resolve(REPO_ROOT, ...paths); diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 6cc21e79ac32db..c84a38cd9dbeee 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -12,12 +12,10 @@ import { statSync } from 'fs'; import { resolve } from 'path'; import url from 'url'; -import { getConfigPath, REPO_ROOT } from '@kbn/utils'; +import { getConfigPath, fromRoot } from '@kbn/utils'; import { IS_KIBANA_DISTRIBUTABLE } from '../../legacy/utils'; import { readKeystore } from '../keystore/read_keystore'; -const fromRoot = (p) => resolve(REPO_ROOT, p); - function canRequire(path) { try { require.resolve(path); diff --git a/src/core/server/http/http_service.ts b/src/core/server/http/http_service.ts index 42f222b6201ff2..5b90440f6ad701 100644 --- a/src/core/server/http/http_service.ts +++ b/src/core/server/http/http_service.ts @@ -153,11 +153,9 @@ export class HttpService } /** - * Indicates if http server has configured to start listening on a configured port. - * We shouldn't start http service in two cases: - * 1. If `server.autoListen` is explicitly set to `false`. - * 2. When the process is run as dev cluster master in which case cluster manager - * will fork a dedicated process where http service will be set up instead. + * Indicates if http server is configured to start listening on a configured port. + * (if `server.autoListen` is not explicitly set to `false`.) + * * @internal * */ private shouldListen(config: HttpConfig) { diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index 92ebd2b957bfa0..8b33e2cf4cc6be 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -115,8 +115,7 @@ export class PluginsService implements CoreService(); - const initialize = config.initialize; - if (initialize) { + if (config.initialize) { contracts = await this.pluginsSystem.setupPlugins(deps); this.registerPluginStaticDirs(deps); } else { @@ -124,7 +123,7 @@ export class PluginsService implements CoreService Date: Mon, 29 Mar 2021 10:44:07 +0200 Subject: [PATCH 31/38] move test to correct file --- src/core/server/http/http_server.test.ts | 24 +++++++++ .../http/integration_tests/router.test.ts | 50 +------------------ 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index 54be7b35f68ad4..ccd14d4b99e112 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -1288,6 +1288,30 @@ test('should return a stream in the body', async () => { }); }); +test('closes sockets on timeout', async () => { + const { registerRouter, server: innerServer } = await server.setup({ + ...config, + socketTimeout: 1000, + }); + const router = new Router('', logger, enhanceWithContext); + + router.get({ path: '/a', validate: false }, async (context, req, res) => { + await new Promise((resolve) => setTimeout(resolve, 2000)); + return res.ok({}); + }); + router.get({ path: '/b', validate: false }, (context, req, res) => res.ok({})); + + registerRouter(router); + + registerRouter(router); + + await server.start(); + + expect(supertest(innerServer.listener).get('/a')).rejects.toThrow('socket hang up'); + + await supertest(innerServer.listener).get('/b').expect(200); +}); + describe('setup contract', () => { describe('#createSessionStorage', () => { test('creates session storage factory', async () => { diff --git a/src/core/server/http/integration_tests/router.test.ts b/src/core/server/http/integration_tests/router.test.ts index 3406d5dbd473f0..5b297ab44f8bbe 100644 --- a/src/core/server/http/integration_tests/router.test.ts +++ b/src/core/server/http/integration_tests/router.test.ts @@ -9,13 +9,11 @@ import { Stream } from 'stream'; import Boom from '@hapi/boom'; import supertest from 'supertest'; -import { ByteSizeValue, schema } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; import { contextServiceMock } from '../../context/context_service.mock'; import { loggingSystemMock } from '../../logging/logging_system.mock'; import { createHttpServer } from '../test_utils'; -import { HttpServer } from '../http_server'; -import { Router } from '../router'; import { HttpService } from '../http_service'; let server: HttpService; @@ -1838,49 +1836,3 @@ describe('ETag', () => { .expect(304, ''); }); }); - -describe('Timeouts', () => { - let httpServer: HttpServer; - let router: Router; - - beforeEach(() => { - httpServer = new HttpServer(logger, 'foo'); - const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, {}); - router = new Router('', logger.get(), enhanceWithContext); - }); - - afterEach(async () => { - await httpServer.stop(); - }); - - test('closes sockets on timeout', async () => { - router.get({ path: '/a', validate: false }, async (context, req, res) => { - await new Promise((resolve) => setTimeout(resolve, 2000)); - return res.ok({}); - }); - router.get({ path: '/b', validate: false }, (context, req, res) => res.ok({})); - - const { registerRouter, server: innerServer } = await httpServer.setup({ - socketTimeout: 1000, - host: '127.0.0.1', - maxPayload: new ByteSizeValue(1024), - ssl: {}, - cors: { - enabled: false, - }, - compression: { enabled: true }, - requestId: { - allowFromAnyIp: true, - ipAllowlist: [], - }, - } as any); - - registerRouter(router); - - await httpServer.start(); - - expect(supertest(innerServer.listener).get('/a')).rejects.toThrow('socket hang up'); - - await supertest(innerServer.listener).get('/b').expect(200); - }); -}); From fd26fbaf023748ffbe19d28852ca4ed0b83482f2 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 29 Mar 2021 10:52:53 +0200 Subject: [PATCH 32/38] add comment on getBootstrapScript --- src/cli/serve/serve.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index c84a38cd9dbeee..86b4ac53841f71 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -242,6 +242,14 @@ export default function (program) { cache: !!opts.cache, dist: !!opts.dist, }; + + // In development mode, the main process uses the @kbn/dev-cli-mode + // bootstrap script instead of core's. The DevCliMode instance + // is in charge of starting up the optimizer, and spawning another + // `/script/kibana` process with the `isDevCliChild` varenv set to true. + // This variable is then used to identify that we're the 'real' + // Kibana server process, and will be using core's bootstrap script + // to effectively start Kibana. const bootstrapScript = getBootstrapScript(cliArgs.dev); await bootstrapScript({ From 107bb390d3d7690b21699ac784ea5b9da06c140e Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 29 Mar 2021 12:39:08 +0200 Subject: [PATCH 33/38] fix lint --- packages/kbn-cli-dev-mode/package.json | 2 +- .../kbn-cli-dev-mode/src/base_path_proxy_server.test.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/kbn-cli-dev-mode/package.json b/packages/kbn-cli-dev-mode/package.json index 0fe711145415b0..d94b9178b640bb 100644 --- a/packages/kbn-cli-dev-mode/package.json +++ b/packages/kbn-cli-dev-mode/package.json @@ -19,10 +19,10 @@ "@kbn/http-tools": "link:../kbn-server-http-tools", "@kbn/optimizer": "link:../kbn-optimizer", "@kbn/std": "link:../kbn-std", + "@kbn/dev-utils": "link:../kbn-dev-utils", "@kbn/utils": "link:../kbn-utils" }, "devDependencies": { - "@kbn/dev-utils": "link:../kbn-dev-utils", "@kbn/utility-types": "link:../kbn-utility-types" } } \ No newline at end of file diff --git a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts index 11637a0b41ff48..c99485c2733645 100644 --- a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts @@ -9,7 +9,12 @@ import { Server } from '@hapi/hapi'; import { EMPTY } from 'rxjs'; import supertest from 'supertest'; -import { getServerOptions, getListenerOptions, createServer, IHttpConfig } from '@kbn/server-http-tools'; +import { + getServerOptions, + getListenerOptions, + createServer, + IHttpConfig, +} from '@kbn/server-http-tools'; import { ByteSizeValue } from '@kbn/config-schema'; import { BasePathProxyServer, BasePathProxyServerOptions } from './base_path_proxy_server'; From 324d2d8e2cc0c0c95bf442fb01f38df06d1f3923 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 29 Mar 2021 17:39:59 +0200 Subject: [PATCH 34/38] lint --- src/core/server/http/http_server.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index d02dc260be0612..cd7d7ccc5aeffa 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -10,7 +10,12 @@ import { Server, Request } from '@hapi/hapi'; import HapiStaticFiles from '@hapi/inert'; import url from 'url'; import uuid from 'uuid'; -import { createServer, getListenerOptions, getServerOptions, getRequestId } from '@kbn/server-http-tools'; +import { + createServer, + getListenerOptions, + getServerOptions, + getRequestId, +} from '@kbn/server-http-tools'; import { Logger, LoggerFactory } from '../logging'; import { HttpConfig } from './http_config'; From dabd6eb8846a35fd523f5979f9a8b2f6ef08dc9f Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 29 Mar 2021 17:43:57 +0200 Subject: [PATCH 35/38] add cli-dev-mode to eslint dev packages --- .eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.js b/.eslintrc.js index ab868c29b7bed8..a7b45534391c0a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -93,6 +93,7 @@ const SAFER_LODASH_SET_DEFINITELYTYPED_HEADER = ` const DEV_PACKAGES = [ 'kbn-babel-code-parser', 'kbn-dev-utils', + 'kbn-cli-dev-mode', 'kbn-docs-utils', 'kbn-es*', 'kbn-eslint*', From 19a018e6437fffe7a6c6598d30b595575903a524 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 29 Mar 2021 21:51:48 +0200 Subject: [PATCH 36/38] review comments --- packages/kbn-cli-dev-mode/package.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/kbn-cli-dev-mode/package.json b/packages/kbn-cli-dev-mode/package.json index d94b9178b640bb..2ee9831e960842 100644 --- a/packages/kbn-cli-dev-mode/package.json +++ b/packages/kbn-cli-dev-mode/package.json @@ -7,7 +7,8 @@ "private": true, "scripts": { "build": "../../node_modules/.bin/tsc", - "kbn:bootstrap": "yarn build" + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" }, "kibana": { "devOnly": true @@ -16,13 +17,10 @@ "@kbn/config": "link:../kbn-config", "@kbn/config-schema": "link:../kbn-config-schema", "@kbn/logging": "link:../kbn-logging", - "@kbn/http-tools": "link:../kbn-server-http-tools", + "@kbn/server-http-tools": "link:../kbn-server-http-tools", "@kbn/optimizer": "link:../kbn-optimizer", "@kbn/std": "link:../kbn-std", "@kbn/dev-utils": "link:../kbn-dev-utils", "@kbn/utils": "link:../kbn-utils" - }, - "devDependencies": { - "@kbn/utility-types": "link:../kbn-utility-types" } } \ No newline at end of file From f47fc07fd578a5d5556dbd262acb8b303a4a7123 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Tue, 30 Mar 2021 00:01:27 +0200 Subject: [PATCH 37/38] update yarn.lock --- yarn.lock | 4 ---- 1 file changed, 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4a76371c6da7fe..0bbfe98f5d1d86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2662,10 +2662,6 @@ version "0.0.0" uid "" -"@kbn/http-tools@link:packages/kbn-server-http-tools": - version "0.0.0" - uid "" - "@kbn/i18n@link:packages/kbn-i18n": version "0.0.0" uid "" From b007289c837abe04cb2a314e994a3b1b9c1f510f Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Tue, 30 Mar 2021 10:12:08 +0200 Subject: [PATCH 38/38] Revert "[ci] skip building ts refs when not necessary (#95739)" This reverts commit e46a74f7 --- .ci/Jenkinsfile_baseline_capture | 1 - test/scripts/checks/type_check.sh | 3 --- vars/workers.groovy | 1 - 3 files changed, 5 deletions(-) diff --git a/.ci/Jenkinsfile_baseline_capture b/.ci/Jenkinsfile_baseline_capture index e017ba54f55950..7fefbbb26fd121 100644 --- a/.ci/Jenkinsfile_baseline_capture +++ b/.ci/Jenkinsfile_baseline_capture @@ -23,7 +23,6 @@ kibanaPipeline(timeoutMinutes: 210) { ) { withGcpServiceAccount.fromVaultSecret('secret/kibana-issues/dev/ci-artifacts-key', 'value') { withEnv([ - 'BUILD_TS_REFS_DISABLE=false', // disabled in root config so we need to override that here 'BUILD_TS_REFS_CACHE_ENABLE=true', 'BUILD_TS_REFS_CACHE_CAPTURE=true', 'DISABLE_BOOTSTRAP_VALIDATION=true', diff --git a/test/scripts/checks/type_check.sh b/test/scripts/checks/type_check.sh index a7ea84d4cadc79..5e091625de4ed0 100755 --- a/test/scripts/checks/type_check.sh +++ b/test/scripts/checks/type_check.sh @@ -2,8 +2,5 @@ source src/dev/ci_setup/setup_env.sh -checks-reporter-with-killswitch "Build TS Refs" \ - node scripts/build_ts_refs --ignore-type-failures --force - checks-reporter-with-killswitch "Check Types" \ node scripts/type_check diff --git a/vars/workers.groovy b/vars/workers.groovy index 1260f74f1bdf9f..5d3328bc8a3c46 100644 --- a/vars/workers.groovy +++ b/vars/workers.groovy @@ -101,7 +101,6 @@ def base(Map params, Closure closure) { "TEST_BROWSER_HEADLESS=1", "GIT_BRANCH=${checkoutInfo.branch}", "TMPDIR=${env.WORKSPACE}/tmp", // For Chrome and anything else that respects it - "BUILD_TS_REFS_DISABLE=true", // no need to build ts refs in bootstrap ]) { withCredentials([ string(credentialsId: 'vault-addr', variable: 'VAULT_ADDR'),