From 886f976a91b52e3a693171c10f851610519eb993 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 3 Apr 2020 11:51:22 -0700 Subject: [PATCH 01/27] New config --- .../__snapshots__/index.test.js.snap | 383 ------------------ x-pack/legacy/plugins/reporting/config.ts | 182 --------- x-pack/legacy/plugins/reporting/index.test.js | 34 -- x-pack/legacy/plugins/reporting/index.ts | 12 - .../plugins/reporting/server/config/config.js | 21 - .../plugins/reporting/server/config/index.ts | 131 +----- .../legacy/plugins/reporting/server/legacy.ts | 10 +- .../lib/esqueue/helpers/index_timestamp.js | 1 + .../legacy/plugins/reporting/server/plugin.ts | 2 - .../plugins/reporting/server/types.d.ts | 3 +- x-pack/plugins/reporting/config.ts | 10 - x-pack/plugins/reporting/kibana.json | 5 +- .../reporting/server/config/index.test.ts | 122 ++++++ .../plugins/reporting/server/config/index.ts | 88 ++++ .../reporting/server/config/schema.test.ts | 103 +++++ .../plugins/reporting/server/config/schema.ts | 174 ++++++++ x-pack/plugins/reporting/server/index.ts | 14 + x-pack/plugins/reporting/server/plugin.ts | 38 ++ 18 files changed, 553 insertions(+), 780 deletions(-) delete mode 100644 x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap delete mode 100644 x-pack/legacy/plugins/reporting/config.ts delete mode 100644 x-pack/legacy/plugins/reporting/index.test.js delete mode 100644 x-pack/legacy/plugins/reporting/server/config/config.js delete mode 100644 x-pack/plugins/reporting/config.ts create mode 100644 x-pack/plugins/reporting/server/config/index.test.ts create mode 100644 x-pack/plugins/reporting/server/config/index.ts create mode 100644 x-pack/plugins/reporting/server/config/schema.test.ts create mode 100644 x-pack/plugins/reporting/server/config/schema.ts create mode 100644 x-pack/plugins/reporting/server/index.ts create mode 100644 x-pack/plugins/reporting/server/plugin.ts diff --git a/x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap b/x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap deleted file mode 100644 index 757677f1d4f82..0000000000000 --- a/x-pack/legacy/plugins/reporting/__snapshots__/index.test.js.snap +++ /dev/null @@ -1,383 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`config schema with context {"dev":false,"dist":false} produces correct config 1`] = ` -Object { - "capture": Object { - "browser": Object { - "autoDownload": true, - "chromium": Object { - "disableSandbox": "", - "maxScreenshotDimension": 1950, - "proxy": Object { - "enabled": false, - }, - }, - "type": "chromium", - }, - "concurrency": 4, - "loadDelay": 3000, - "maxAttempts": 1, - "networkPolicy": Object { - "enabled": true, - "rules": Array [ - Object { - "allow": true, - "protocol": "http:", - }, - Object { - "allow": true, - "protocol": "https:", - }, - Object { - "allow": true, - "protocol": "ws:", - }, - Object { - "allow": true, - "protocol": "wss:", - }, - Object { - "allow": true, - "protocol": "data:", - }, - Object { - "allow": false, - }, - ], - }, - "settleTime": 1000, - "timeout": 20000, - "timeouts": Object { - "openUrl": 30000, - "renderComplete": 30000, - "waitForElements": 30000, - }, - "viewport": Object { - "height": 1200, - "width": 1950, - }, - "zoom": 2, - }, - "csv": Object { - "checkForFormulas": true, - "enablePanelActionDownload": true, - "maxSizeBytes": 10485760, - "scroll": Object { - "duration": "30s", - "size": 500, - }, - }, - "enabled": true, - "encryptionKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "index": ".reporting", - "kibanaServer": Object {}, - "poll": Object { - "jobCompletionNotifier": Object { - "interval": 10000, - "intervalErrorMultiplier": 5, - }, - "jobsRefresh": Object { - "interval": 5000, - "intervalErrorMultiplier": 5, - }, - }, - "queue": Object { - "indexInterval": "week", - "pollEnabled": true, - "pollInterval": 3000, - "pollIntervalErrorMultiplier": 10, - "timeout": 120000, - }, - "roles": Object { - "allow": Array [ - "reporting_user", - ], - }, -} -`; - -exports[`config schema with context {"dev":false,"dist":true} produces correct config 1`] = ` -Object { - "capture": Object { - "browser": Object { - "autoDownload": false, - "chromium": Object { - "disableSandbox": "", - "maxScreenshotDimension": 1950, - "proxy": Object { - "enabled": false, - }, - }, - "type": "chromium", - }, - "concurrency": 4, - "loadDelay": 3000, - "maxAttempts": 3, - "networkPolicy": Object { - "enabled": true, - "rules": Array [ - Object { - "allow": true, - "protocol": "http:", - }, - Object { - "allow": true, - "protocol": "https:", - }, - Object { - "allow": true, - "protocol": "ws:", - }, - Object { - "allow": true, - "protocol": "wss:", - }, - Object { - "allow": true, - "protocol": "data:", - }, - Object { - "allow": false, - }, - ], - }, - "settleTime": 1000, - "timeout": 20000, - "timeouts": Object { - "openUrl": 30000, - "renderComplete": 30000, - "waitForElements": 30000, - }, - "viewport": Object { - "height": 1200, - "width": 1950, - }, - "zoom": 2, - }, - "csv": Object { - "checkForFormulas": true, - "enablePanelActionDownload": true, - "maxSizeBytes": 10485760, - "scroll": Object { - "duration": "30s", - "size": 500, - }, - }, - "enabled": true, - "index": ".reporting", - "kibanaServer": Object {}, - "poll": Object { - "jobCompletionNotifier": Object { - "interval": 10000, - "intervalErrorMultiplier": 5, - }, - "jobsRefresh": Object { - "interval": 5000, - "intervalErrorMultiplier": 5, - }, - }, - "queue": Object { - "indexInterval": "week", - "pollEnabled": true, - "pollInterval": 3000, - "pollIntervalErrorMultiplier": 10, - "timeout": 120000, - }, - "roles": Object { - "allow": Array [ - "reporting_user", - ], - }, -} -`; - -exports[`config schema with context {"dev":true,"dist":false} produces correct config 1`] = ` -Object { - "capture": Object { - "browser": Object { - "autoDownload": true, - "chromium": Object { - "disableSandbox": "", - "maxScreenshotDimension": 1950, - "proxy": Object { - "enabled": false, - }, - }, - "type": "chromium", - }, - "concurrency": 4, - "loadDelay": 3000, - "maxAttempts": 1, - "networkPolicy": Object { - "enabled": true, - "rules": Array [ - Object { - "allow": true, - "protocol": "http:", - }, - Object { - "allow": true, - "protocol": "https:", - }, - Object { - "allow": true, - "protocol": "ws:", - }, - Object { - "allow": true, - "protocol": "wss:", - }, - Object { - "allow": true, - "protocol": "data:", - }, - Object { - "allow": false, - }, - ], - }, - "settleTime": 1000, - "timeout": 20000, - "timeouts": Object { - "openUrl": 30000, - "renderComplete": 30000, - "waitForElements": 30000, - }, - "viewport": Object { - "height": 1200, - "width": 1950, - }, - "zoom": 2, - }, - "csv": Object { - "checkForFormulas": true, - "enablePanelActionDownload": true, - "maxSizeBytes": 10485760, - "scroll": Object { - "duration": "30s", - "size": 500, - }, - }, - "enabled": true, - "encryptionKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "index": ".reporting", - "kibanaServer": Object {}, - "poll": Object { - "jobCompletionNotifier": Object { - "interval": 10000, - "intervalErrorMultiplier": 5, - }, - "jobsRefresh": Object { - "interval": 5000, - "intervalErrorMultiplier": 5, - }, - }, - "queue": Object { - "indexInterval": "week", - "pollEnabled": true, - "pollInterval": 3000, - "pollIntervalErrorMultiplier": 10, - "timeout": 120000, - }, - "roles": Object { - "allow": Array [ - "reporting_user", - ], - }, -} -`; - -exports[`config schema with context {"dev":true,"dist":true} produces correct config 1`] = ` -Object { - "capture": Object { - "browser": Object { - "autoDownload": false, - "chromium": Object { - "disableSandbox": "", - "maxScreenshotDimension": 1950, - "proxy": Object { - "enabled": false, - }, - }, - "type": "chromium", - }, - "concurrency": 4, - "loadDelay": 3000, - "maxAttempts": 3, - "networkPolicy": Object { - "enabled": true, - "rules": Array [ - Object { - "allow": true, - "protocol": "http:", - }, - Object { - "allow": true, - "protocol": "https:", - }, - Object { - "allow": true, - "protocol": "ws:", - }, - Object { - "allow": true, - "protocol": "wss:", - }, - Object { - "allow": true, - "protocol": "data:", - }, - Object { - "allow": false, - }, - ], - }, - "settleTime": 1000, - "timeout": 20000, - "timeouts": Object { - "openUrl": 30000, - "renderComplete": 30000, - "waitForElements": 30000, - }, - "viewport": Object { - "height": 1200, - "width": 1950, - }, - "zoom": 2, - }, - "csv": Object { - "checkForFormulas": true, - "enablePanelActionDownload": true, - "maxSizeBytes": 10485760, - "scroll": Object { - "duration": "30s", - "size": 500, - }, - }, - "enabled": true, - "index": ".reporting", - "kibanaServer": Object {}, - "poll": Object { - "jobCompletionNotifier": Object { - "interval": 10000, - "intervalErrorMultiplier": 5, - }, - "jobsRefresh": Object { - "interval": 5000, - "intervalErrorMultiplier": 5, - }, - }, - "queue": Object { - "indexInterval": "week", - "pollEnabled": true, - "pollInterval": 3000, - "pollIntervalErrorMultiplier": 10, - "timeout": 120000, - }, - "roles": Object { - "allow": Array [ - "reporting_user", - ], - }, -} -`; diff --git a/x-pack/legacy/plugins/reporting/config.ts b/x-pack/legacy/plugins/reporting/config.ts deleted file mode 100644 index 211fa70301bbf..0000000000000 --- a/x-pack/legacy/plugins/reporting/config.ts +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { BROWSER_TYPE } from './common/constants'; -// @ts-ignore untyped module -import { config as appConfig } from './server/config/config'; -import { getDefaultChromiumSandboxDisabled } from './server/browsers'; - -export async function config(Joi: any) { - return Joi.object({ - enabled: Joi.boolean().default(true), - kibanaServer: Joi.object({ - protocol: Joi.string().valid(['http', 'https']), - hostname: Joi.string().invalid('0'), - port: Joi.number().integer(), - }).default(), - queue: Joi.object({ - indexInterval: Joi.string().default('week'), - pollEnabled: Joi.boolean().default(true), - pollInterval: Joi.number() - .integer() - .default(3000), - pollIntervalErrorMultiplier: Joi.number() - .integer() - .default(10), - timeout: Joi.number() - .integer() - .default(120000), - }).default(), - capture: Joi.object({ - timeouts: Joi.object({ - openUrl: Joi.number() - .integer() - .default(30000), - waitForElements: Joi.number() - .integer() - .default(30000), - renderComplete: Joi.number() - .integer() - .default(30000), - }).default(), - networkPolicy: Joi.object({ - enabled: Joi.boolean().default(true), - rules: Joi.array() - .items( - Joi.object({ - allow: Joi.boolean().required(), - protocol: Joi.string(), - host: Joi.string(), - }) - ) - .default([ - { allow: true, protocol: 'http:' }, - { allow: true, protocol: 'https:' }, - { allow: true, protocol: 'ws:' }, - { allow: true, protocol: 'wss:' }, - { allow: true, protocol: 'data:' }, - { allow: false }, // Default action is to deny! - ]), - }).default(), - zoom: Joi.number() - .integer() - .default(2), - viewport: Joi.object({ - width: Joi.number() - .integer() - .default(1950), - height: Joi.number() - .integer() - .default(1200), - }).default(), - timeout: Joi.number() - .integer() - .default(20000), // deprecated - loadDelay: Joi.number() - .integer() - .default(3000), - settleTime: Joi.number() - .integer() - .default(1000), // deprecated - concurrency: Joi.number() - .integer() - .default(appConfig.concurrency), // deprecated - browser: Joi.object({ - type: Joi.any() - .valid(BROWSER_TYPE) - .default(BROWSER_TYPE), - autoDownload: Joi.boolean().when('$dist', { - is: true, - then: Joi.default(false), - otherwise: Joi.default(true), - }), - chromium: Joi.object({ - inspect: Joi.boolean() - .when('$dev', { - is: false, - then: Joi.valid(false), - else: Joi.default(false), - }) - .default(), - disableSandbox: Joi.boolean().default(await getDefaultChromiumSandboxDisabled()), - proxy: Joi.object({ - enabled: Joi.boolean().default(false), - server: Joi.string() - .uri({ scheme: ['http', 'https'] }) - .when('enabled', { - is: Joi.valid(false), - then: Joi.valid(null), - else: Joi.required(), - }), - bypass: Joi.array() - .items(Joi.string().regex(/^[^\s]+$/)) - .when('enabled', { - is: Joi.valid(false), - then: Joi.valid(null), - else: Joi.default([]), - }), - }).default(), - maxScreenshotDimension: Joi.number() - .integer() - .default(1950), - }).default(), - }).default(), - maxAttempts: Joi.number() - .integer() - .greater(0) - .when('$dist', { - is: true, - then: Joi.default(3), - otherwise: Joi.default(1), - }) - .default(), - }).default(), - csv: Joi.object({ - checkForFormulas: Joi.boolean().default(true), - enablePanelActionDownload: Joi.boolean().default(true), - maxSizeBytes: Joi.number() - .integer() - .default(1024 * 1024 * 10), // bytes in a kB * kB in a mB * 10 - scroll: Joi.object({ - duration: Joi.string() - .regex(/^[0-9]+(d|h|m|s|ms|micros|nanos)$/, { name: 'DurationString' }) - .default('30s'), - size: Joi.number() - .integer() - .default(500), - }).default(), - }).default(), - encryptionKey: Joi.when(Joi.ref('$dist'), { - is: true, - then: Joi.string(), - otherwise: Joi.string().default('a'.repeat(32)), - }), - roles: Joi.object({ - allow: Joi.array() - .items(Joi.string()) - .default(['reporting_user']), - }).default(), - index: Joi.string().default('.reporting'), - poll: Joi.object({ - jobCompletionNotifier: Joi.object({ - interval: Joi.number() - .integer() - .default(10000), - intervalErrorMultiplier: Joi.number() - .integer() - .default(5), - }).default(), - jobsRefresh: Joi.object({ - interval: Joi.number() - .integer() - .default(5000), - intervalErrorMultiplier: Joi.number() - .integer() - .default(5), - }).default(), - }).default(), - }).default(); -} diff --git a/x-pack/legacy/plugins/reporting/index.test.js b/x-pack/legacy/plugins/reporting/index.test.js deleted file mode 100644 index 0d9a717bd7d81..0000000000000 --- a/x-pack/legacy/plugins/reporting/index.test.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { reporting } from './index'; -import { getConfigSchema } from '../../../test_utils'; - -// The snapshot records the number of cpus available -// to make the snapshot deterministic `os.cpus` needs to be mocked -// but the other members on `os` must remain untouched -jest.mock('os', () => { - const os = jest.requireActual('os'); - os.cpus = () => [{}, {}, {}, {}]; - return os; -}); - -// eslint-disable-next-line jest/valid-describe -const describeWithContext = describe.each([ - [{ dev: false, dist: false }], - [{ dev: true, dist: false }], - [{ dev: false, dist: true }], - [{ dev: true, dist: true }], -]); - -describeWithContext('config schema with context %j', context => { - it('produces correct config', async () => { - const schema = await getConfigSchema(reporting); - const value = await schema.validate({}, { context }); - value.capture.browser.chromium.disableSandbox = ''; - await expect(value).toMatchSnapshot(); - }); -}); diff --git a/x-pack/legacy/plugins/reporting/index.ts b/x-pack/legacy/plugins/reporting/index.ts index a5d27d0545da1..fb95e2c2edc24 100644 --- a/x-pack/legacy/plugins/reporting/index.ts +++ b/x-pack/legacy/plugins/reporting/index.ts @@ -8,7 +8,6 @@ import { i18n } from '@kbn/i18n'; import { Legacy } from 'kibana'; import { resolve } from 'path'; import { PLUGIN_ID, UI_SETTINGS_CUSTOM_PDF_LOGO } from './common/constants'; -import { config as reportingConfig } from './config'; import { legacyInit } from './server/legacy'; import { ReportingPluginSpecOptions } from './types'; @@ -17,10 +16,8 @@ const kbToBase64Length = (kb: number) => Math.floor((kb * 1024 * 8) / 6); export const reporting = (kibana: any) => { return new kibana.Plugin({ id: PLUGIN_ID, - configPrefix: 'xpack.reporting', publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], - config: reportingConfig, uiExports: { uiSettingDefaults: { @@ -47,14 +44,5 @@ export const reporting = (kibana: any) => { async init(server: Legacy.Server) { return legacyInit(server, this); }, - - deprecations({ unused }: any) { - return [ - unused('capture.concurrency'), - unused('capture.timeout'), - unused('capture.settleTime'), - unused('kibanaApp'), - ]; - }, } as ReportingPluginSpecOptions); }; diff --git a/x-pack/legacy/plugins/reporting/server/config/config.js b/x-pack/legacy/plugins/reporting/server/config/config.js deleted file mode 100644 index 08e4db464b003..0000000000000 --- a/x-pack/legacy/plugins/reporting/server/config/config.js +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { cpus } from 'os'; - -const defaultCPUCount = 2; - -function cpuCount() { - try { - return cpus().length; - } catch (e) { - return defaultCPUCount; - } -} - -export const config = { - concurrency: cpuCount(), -}; diff --git a/x-pack/legacy/plugins/reporting/server/config/index.ts b/x-pack/legacy/plugins/reporting/server/config/index.ts index 623d3c2015f3b..a0ff4500e87b5 100644 --- a/x-pack/legacy/plugins/reporting/server/config/index.ts +++ b/x-pack/legacy/plugins/reporting/server/config/index.ts @@ -6,10 +6,8 @@ import { Legacy } from 'kibana'; import { CoreSetup } from 'src/core/server'; -import { i18n } from '@kbn/i18n'; -import crypto from 'crypto'; import { get } from 'lodash'; -import { NetworkPolicy } from '../../types'; +import { ConfigType as ReportingConfigType } from '../../../../../plugins/reporting/server'; // make config.get() aware of the value type it returns interface Config { @@ -56,130 +54,6 @@ export interface ReportingConfig extends Config { kbnConfig: Config; } -type BrowserType = 'chromium'; - -interface BrowserConfig { - inspect: boolean; - userDataDir: string; - viewport: { width: number; height: number }; - disableSandbox: boolean; - proxy: { - enabled: boolean; - server?: string; - bypass?: string[]; - }; -} - -interface CaptureConfig { - browser: { - type: BrowserType; - autoDownload: boolean; - chromium: BrowserConfig; - }; - maxAttempts: number; - networkPolicy: NetworkPolicy; - loadDelay: number; - timeouts: { - openUrl: number; - waitForElements: number; - renderComplete: number; - }; - viewport: any; - zoom: any; -} - -interface QueueConfig { - indexInterval: string; - pollEnabled: boolean; - pollInterval: number; - pollIntervalErrorMultiplier: number; - timeout: number; -} - -interface ScrollConfig { - duration: string; - size: number; -} - -export interface ReportingConfigType { - capture: CaptureConfig; - csv: { - scroll: ScrollConfig; - enablePanelActionDownload: boolean; - checkForFormulas: boolean; - maxSizeBytes: number; - }; - encryptionKey: string; - kibanaServer: any; - index: string; - queue: QueueConfig; - roles: any; -} - -const addConfigDefaults = ( - server: Legacy.Server, - core: CoreSetup, - baseConfig: ReportingConfigType -) => { - // encryption key - let encryptionKey = baseConfig.encryptionKey; - if (encryptionKey === undefined) { - server.log( - ['reporting', 'config', 'warning'], - i18n.translate('xpack.reporting.selfCheckEncryptionKey.warning', { - defaultMessage: - `Generating a random key for {setting}. To prevent pending reports ` + - `from failing on restart, please set {setting} in kibana.yml`, - values: { - setting: 'xpack.reporting.encryptionKey', - }, - }) - ); - encryptionKey = crypto.randomBytes(16).toString('hex'); - } - - const { kibanaServer: reportingServer } = baseConfig; - const serverInfo = core.http.getServerInfo(); - - // kibanaServer.hostname, default to server.host, don't allow "0" - let kibanaServerHostname = reportingServer.hostname ? reportingServer.hostname : serverInfo.host; - if (kibanaServerHostname === '0') { - server.log( - ['reporting', 'config', 'warning'], - i18n.translate('xpack.reporting.selfCheckHostname.warning', { - defaultMessage: - `Found 'server.host: "0"' in settings. This is incompatible with Reporting. ` + - `To enable Reporting to work, '{setting}: 0.0.0.0' is being automatically to the configuration. ` + - `You can change to 'server.host: 0.0.0.0' or add '{setting}: 0.0.0.0' in kibana.yml to prevent this message.`, - values: { - setting: 'xpack.reporting.kibanaServer.hostname', - }, - }) - ); - kibanaServerHostname = '0.0.0.0'; - } - - // kibanaServer.port, default to server.port - const kibanaServerPort = reportingServer.port - ? reportingServer.port - : serverInfo.port; // prettier-ignore - - // kibanaServer.protocol, default to server.protocol - const kibanaServerProtocol = reportingServer.protocol - ? reportingServer.protocol - : serverInfo.protocol; - - return { - ...baseConfig, - encryptionKey, - kibanaServer: { - hostname: kibanaServerHostname, - port: kibanaServerPort, - protocol: kibanaServerProtocol, - }, - }; -}; - export const buildConfig = ( core: CoreSetup, server: Legacy.Server, @@ -204,7 +78,6 @@ export const buildConfig = ( }; // spreading arguments as an array allows the return type to be known by the compiler - reportingConfig = addConfigDefaults(server, core, reportingConfig); return { get: (...keys: string[]) => get(reportingConfig, keys.join('.'), null), kbnConfig: { @@ -212,3 +85,5 @@ export const buildConfig = ( }, }; }; + +export { ReportingConfigType }; diff --git a/x-pack/legacy/plugins/reporting/server/legacy.ts b/x-pack/legacy/plugins/reporting/server/legacy.ts index 679b42aca6de5..d044dc866ed0e 100644 --- a/x-pack/legacy/plugins/reporting/server/legacy.ts +++ b/x-pack/legacy/plugins/reporting/server/legacy.ts @@ -5,7 +5,9 @@ */ import { Legacy } from 'kibana'; +import { take } from 'rxjs/operators'; import { PluginInitializerContext } from 'src/core/server'; +import { PluginsSetup } from '../../../../plugins/reporting/server'; import { SecurityPluginSetup } from '../../../../plugins/security/server'; import { ReportingPluginSpecOptions } from '../types'; import { buildConfig } from './config'; @@ -17,7 +19,6 @@ const buildLegacyDependencies = ( reportingPlugin: ReportingPluginSpecOptions ): LegacySetup => ({ route: server.route.bind(server), - config: server.config, plugins: { xpack_main: server.plugins.xpack_main, reporting: reportingPlugin, @@ -32,14 +33,13 @@ export const legacyInit = async ( reportingLegacyPlugin: ReportingPluginSpecOptions ) => { const { core: coreSetup } = server.newPlatform.setup; - const legacyConfig = server.config(); - const reportingConfig = buildConfig(coreSetup, server, legacyConfig.get('xpack.reporting')); - + const { config$ } = (server.newPlatform.setup.plugins.reporting as PluginsSetup).__legacy; + const reportingConfig = await config$.pipe(take(1)).toPromise(); const __LEGACY = buildLegacyDependencies(server, reportingLegacyPlugin); const pluginInstance = plugin( server.newPlatform.coreContext as PluginInitializerContext, - reportingConfig + buildConfig(coreSetup, server, reportingConfig) ); await pluginInstance.setup(coreSetup, { elasticsearch: coreSetup.elasticsearch, diff --git a/x-pack/legacy/plugins/reporting/server/lib/esqueue/helpers/index_timestamp.js b/x-pack/legacy/plugins/reporting/server/lib/esqueue/helpers/index_timestamp.js index 6cdbe8f968f75..8e4047e2f22e5 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/esqueue/helpers/index_timestamp.js +++ b/x-pack/legacy/plugins/reporting/server/lib/esqueue/helpers/index_timestamp.js @@ -8,6 +8,7 @@ import moment from 'moment'; export const intervals = ['year', 'month', 'week', 'day', 'hour', 'minute']; +// TODO: remove this helper by using `schema.duration` objects in the reporting config schema export function indexTimestamp(intervalStr, separator = '-') { if (separator.match(/[a-z]/i)) throw new Error('Interval separator can not be a letter'); diff --git a/x-pack/legacy/plugins/reporting/server/plugin.ts b/x-pack/legacy/plugins/reporting/server/plugin.ts index c9ed2e81c6792..99241f8a3ab2c 100644 --- a/x-pack/legacy/plugins/reporting/server/plugin.ts +++ b/x-pack/legacy/plugins/reporting/server/plugin.ts @@ -12,8 +12,6 @@ import { createQueueFactory, enqueueJobFactory, LevelLogger, runValidations } fr import { setFieldFormats } from './services'; import { ReportingSetup, ReportingSetupDeps, ReportingStart, ReportingStartDeps } from './types'; import { registerReportingUsageCollector } from './usage'; -// @ts-ignore no module definition -import { mirrorPluginStatus } from '../../../server/lib/mirror_plugin_status'; export class ReportingPlugin implements Plugin { diff --git a/x-pack/legacy/plugins/reporting/server/types.d.ts b/x-pack/legacy/plugins/reporting/server/types.d.ts index bec00688432cc..fb77eae4e7eea 100644 --- a/x-pack/legacy/plugins/reporting/server/types.d.ts +++ b/x-pack/legacy/plugins/reporting/server/types.d.ts @@ -11,7 +11,7 @@ import { PluginStart as DataPluginStart } from '../../../../../src/plugins/data/ import { SecurityPluginSetup } from '../../../../plugins/security/server'; import { XPackMainPlugin } from '../../xpack_main/server/xpack_main'; import { ReportingPluginSpecOptions } from '../types'; -import { ReportingConfig, ReportingConfigType } from './core'; +import { ReportingConfigType } from './core'; export interface ReportingSetupDeps { elasticsearch: ElasticsearchServiceSetup; @@ -30,7 +30,6 @@ export type ReportingSetup = object; export type ReportingStart = object; export interface LegacySetup { - config: Legacy.Server['config']; plugins: { xpack_main: XPackMainPlugin & { status?: any; diff --git a/x-pack/plugins/reporting/config.ts b/x-pack/plugins/reporting/config.ts deleted file mode 100644 index f1d6b1a8f248f..0000000000000 --- a/x-pack/plugins/reporting/config.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export const reportingPollConfig = { - jobCompletionNotifier: { interval: 10000, intervalErrorMultiplier: 5 }, - jobsRefresh: { interval: 5000, intervalErrorMultiplier: 5 }, -}; diff --git a/x-pack/plugins/reporting/kibana.json b/x-pack/plugins/reporting/kibana.json index 3da2d2a094706..d068711b87c9d 100644 --- a/x-pack/plugins/reporting/kibana.json +++ b/x-pack/plugins/reporting/kibana.json @@ -2,6 +2,9 @@ "id": "reporting", "version": "8.0.0", "kibanaVersion": "kibana", + "optionalPlugins": [ + "usageCollection" + ], "configPath": ["xpack", "reporting"], "requiredPlugins": [ "home", @@ -12,6 +15,6 @@ "share", "kibanaLegacy" ], - "server": false, + "server": true, "ui": true } diff --git a/x-pack/plugins/reporting/server/config/index.test.ts b/x-pack/plugins/reporting/server/config/index.test.ts new file mode 100644 index 0000000000000..08fe2c5861311 --- /dev/null +++ b/x-pack/plugins/reporting/server/config/index.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as Rx from 'rxjs'; +import { CoreSetup, Logger, PluginInitializerContext } from '../../../../../src/core/server'; +import { createConfig$ } from './'; + +interface KibanaServer { + host?: string; + port?: number; + protocol?: string; +} +interface ReportingKibanaServer { + hostname?: string; + port?: number; + protocol?: string; +} + +const makeMockInitContext = (config: { + encryptionKey?: string; + kibanaServer: ReportingKibanaServer; +}): PluginInitializerContext => + ({ + config: { create: () => Rx.of(config) }, + } as PluginInitializerContext); + +const makeMockCoreSetup = (serverInfo: KibanaServer): CoreSetup => + ({ http: { getServerInfo: () => serverInfo } } as any); + +describe('Reporting server createConfig$', () => { + let mockCoreSetup: CoreSetup; + let mockInitContext: PluginInitializerContext; + let mockLogger: Logger; + + beforeEach(() => { + mockCoreSetup = makeMockCoreSetup({ host: 'kibanaHost', port: 5601, protocol: 'http' }); + mockInitContext = makeMockInitContext({ + kibanaServer: {}, + }); + mockLogger = ({ warn: jest.fn() } as unknown) as Logger; + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('creates random encryption key and default config using host, protocol, and port from server info', async () => { + const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + + expect(result.encryptionKey).toMatch(/\S{32,}/); + expect(result.kibanaServer).toMatchInlineSnapshot(` + Object { + "hostname": "kibanaHost", + "port": 5601, + "protocol": "http", + } + `); + expect((mockLogger.warn as any).mock.calls.length).toBe(1); + expect((mockLogger.warn as any).mock.calls[0]).toMatchObject([ + 'Generating a random key for xpack.reporting.encryptionKey. To prevent sessions from being invalidated on restart, please set xpack.reporting.encryptionKey in kibana.yml', + ]); + }); + + it('uses the encryption key', async () => { + mockInitContext = makeMockInitContext({ + encryptionKey: 'iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii', + kibanaServer: {}, + }); + const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + + expect(result.encryptionKey).toMatch('iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii'); + expect((mockLogger.warn as any).mock.calls.length).toBe(0); + }); + + it('uses the encryption key, reporting kibanaServer settings to override server info', async () => { + mockInitContext = makeMockInitContext({ + encryptionKey: 'iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii', + kibanaServer: { + hostname: 'reportingHost', + port: 5677, + protocol: 'httpsa', + }, + }); + const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + + expect(result).toMatchInlineSnapshot(` + Object { + "encryptionKey": "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii", + "kibanaServer": Object { + "hostname": "reportingHost", + "port": 5677, + "protocol": "httpsa", + }, + } + `); + expect((mockLogger.warn as any).mock.calls.length).toBe(0); + }); + + it('show warning when kibanaServer.hostName === "0"', async () => { + mockInitContext = makeMockInitContext({ + encryptionKey: 'aaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaa', + kibanaServer: { hostname: '0' }, + }); + const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + + expect(result.kibanaServer).toMatchInlineSnapshot(` + Object { + "hostname": "0.0.0.0", + "port": 5601, + "protocol": "http", + } + `); + expect((mockLogger.warn as any).mock.calls.length).toBe(1); + expect((mockLogger.warn as any).mock.calls[0]).toMatchObject([ + `Found 'server.host: \"0\" in Kibana configuration. This is incompatible with Reporting. To enable Reporting to work, 'xpack.reporting.kibanaServer.hostname: 0.0.0.0' is being automatically ` + + `to the configuration. You can change the setting to 'server.host: 0.0.0.0' or add 'xpack.reporting.kibanaServer.hostname: 0.0.0.0' in kibana.yml to prevent this message.`, + ]); + }); +}); diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts new file mode 100644 index 0000000000000..bc28e962ed011 --- /dev/null +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n/'; +import { TypeOf } from '@kbn/config-schema'; +import crypto from 'crypto'; +import { map } from 'rxjs/operators'; +import { PluginConfigDescriptor } from 'kibana/server'; +import { CoreSetup, Logger, PluginInitializerContext } from '../../../../../src/core/server'; +import { ConfigSchema, ConfigType } from './schema'; + +/* + * Set up dynamic config defaults + */ +export function createConfig$(core: CoreSetup, context: PluginInitializerContext, logger: Logger) { + return context.config.create>().pipe( + map(config => { + // encryption key + let encryptionKey = config.encryptionKey; + if (encryptionKey === undefined) { + logger.warn( + i18n.translate('xpack.reporting.serverConfig.randomEncryptionKey', { + defaultMessage: + 'Generating a random key for xpack.reporting.encryptionKey. To prevent sessions from being invalidated on ' + + 'restart, please set xpack.reporting.encryptionKey in kibana.yml', + }) + ); + encryptionKey = crypto.randomBytes(16).toString('hex'); + } + + const { kibanaServer: reportingServer } = config; + const serverInfo = core.http.getServerInfo(); + + // kibanaServer.hostname, default to server.host, don't allow "0" + let kibanaServerHostname = reportingServer.hostname + ? reportingServer.hostname + : serverInfo.host; + if (kibanaServerHostname === '0') { + logger.warn( + i18n.translate('xpack.reporting.serverConfig.invalidServerHostname', { + defaultMessage: + `Found 'server.host: "0" in Kibana configuration. This is incompatible with Reporting. ` + + `To enable Reporting to work, '{configKey}: 0.0.0.0' is being automatically to the configuration. ` + + `You can change the setting to 'server.host: 0.0.0.0' or add '{configKey}: 0.0.0.0' in kibana.yml to prevent this message.`, + values: { configKey: 'xpack.reporting.kibanaServer.hostname' }, + }) + ); + kibanaServerHostname = '0.0.0.0'; + } + + // kibanaServer.port, default to server.port + const kibanaServerPort = reportingServer.port + ? reportingServer.port + : serverInfo.port; // prettier-ignore + + // kibanaServer.protocol, default to server.protocol + const kibanaServerProtocol = reportingServer.protocol + ? reportingServer.protocol + : serverInfo.protocol; + + return { + ...config, + encryptionKey, + kibanaServer: { + hostname: kibanaServerHostname, + port: kibanaServerPort, + protocol: kibanaServerProtocol, + }, + }; + }) + ); +} + +export const config: PluginConfigDescriptor = { + schema: ConfigSchema, + deprecations: ({ unused }) => [ + unused('capture.browser.chromium.maxScreenshotDimension'), + unused('capture.concurrency'), + unused('capture.settleTime'), + unused('capture.timeout'), + unused('kibanaApp'), + ], +}; + +export { ConfigSchema, ConfigType }; diff --git a/x-pack/plugins/reporting/server/config/schema.test.ts b/x-pack/plugins/reporting/server/config/schema.test.ts new file mode 100644 index 0000000000000..d8fe6d1ff084a --- /dev/null +++ b/x-pack/plugins/reporting/server/config/schema.test.ts @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ConfigSchema } from './schema'; + +describe('Reporting Config Schema', () => { + it(`context {"dev":false,"dist":false} produces correct config`, () => { + expect(ConfigSchema.validate({}, { dev: false, dist: false })).toMatchObject({ + capture: { + browser: { + autoDownload: true, + chromium: { disableSandbox: false, proxy: { enabled: false } }, + type: 'chromium', + }, + loadDelay: 3000, + maxAttempts: 1, + networkPolicy: { + enabled: true, + rules: [ + { allow: true, host: undefined, protocol: 'http:' }, + { allow: true, host: undefined, protocol: 'https:' }, + { allow: true, host: undefined, protocol: 'ws:' }, + { allow: true, host: undefined, protocol: 'wss:' }, + { allow: true, host: undefined, protocol: 'data:' }, + { allow: false, host: undefined, protocol: undefined }, + ], + }, + viewport: { height: 1200, width: 1950 }, + zoom: 2, + }, + csv: { + checkForFormulas: true, + enablePanelActionDownload: true, + maxSizeBytes: 10485760, + scroll: { duration: '30s', size: 500 }, + }, + encryptionKey: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + index: '.reporting', + kibanaServer: {}, + poll: { + jobCompletionNotifier: { interval: 10000, intervalErrorMultiplier: 5 }, + jobsRefresh: { interval: 5000, intervalErrorMultiplier: 5 }, + }, + queue: { + indexInterval: 'week', + pollEnabled: true, + pollInterval: 3000, + pollIntervalErrorMultiplier: 10, + timeout: 120000, + }, + roles: { allow: ['reporting_user'] }, + }); + }); + it(`context {"dev":false,"dist":true} produces correct config`, () => { + expect(ConfigSchema.validate({}, { dev: false, dist: true })).toMatchObject({ + capture: { + browser: { + autoDownload: false, + chromium: { disableSandbox: false, inspect: false, proxy: { enabled: false } }, + type: 'chromium', + }, + loadDelay: 3000, + maxAttempts: 3, + networkPolicy: { + enabled: true, + rules: [ + { allow: true, host: undefined, protocol: 'http:' }, + { allow: true, host: undefined, protocol: 'https:' }, + { allow: true, host: undefined, protocol: 'ws:' }, + { allow: true, host: undefined, protocol: 'wss:' }, + { allow: true, host: undefined, protocol: 'data:' }, + { allow: false, host: undefined, protocol: undefined }, + ], + }, + viewport: { height: 1200, width: 1950 }, + zoom: 2, + }, + csv: { + checkForFormulas: true, + enablePanelActionDownload: true, + maxSizeBytes: 10485760, + scroll: { duration: '30s', size: 500 }, + }, + index: '.reporting', + kibanaServer: {}, + poll: { + jobCompletionNotifier: { interval: 10000, intervalErrorMultiplier: 5 }, + jobsRefresh: { interval: 5000, intervalErrorMultiplier: 5 }, + }, + queue: { + indexInterval: 'week', + pollEnabled: true, + pollInterval: 3000, + pollIntervalErrorMultiplier: 10, + timeout: 120000, + }, + roles: { allow: ['reporting_user'] }, + }); + }); +}); diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts new file mode 100644 index 0000000000000..0058b7a5096f0 --- /dev/null +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import moment from 'moment'; + +const KibanaServerSchema = schema.object({ + hostname: schema.maybe( + schema.string({ + validate(value) { + if (value === '0') { + return 'must not be "0" for the headless browser to correctly resolve the host'; + } + }, + hostname: true, + }) + ), + port: schema.maybe(schema.number()), + protocol: schema.maybe( + schema.string({ + validate(value) { + if (!/^https?$/.test(value)) { + return 'must be "http" or "https"'; + } + }, + }) + ), +}); + +const QueueSchema = schema.object({ + indexInterval: schema.string({ defaultValue: 'week' }), + pollEnabled: schema.boolean({ defaultValue: true }), + pollInterval: schema.number({ defaultValue: 3000 }), + pollIntervalErrorMultiplier: schema.number({ defaultValue: 10 }), + timeout: schema.number({ defaultValue: moment.duration(2, 'm').asMilliseconds() }), +}); + +const RulesSchema = schema.object({ + allow: schema.boolean(), + host: schema.maybe(schema.string()), + protocol: schema.maybe(schema.string()), +}); + +const CaptureSchema = schema.object({ + timeouts: schema.object({ + openUrl: schema.number({ defaultValue: 30000 }), + waitForElements: schema.number({ defaultValue: 30000 }), + renderComplete: schema.number({ defaultValue: 30000 }), + }), + networkPolicy: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + rules: schema.arrayOf(RulesSchema, { + defaultValue: [ + { host: undefined, allow: true, protocol: 'http:' }, + { host: undefined, allow: true, protocol: 'https:' }, + { host: undefined, allow: true, protocol: 'ws:' }, + { host: undefined, allow: true, protocol: 'wss:' }, + { host: undefined, allow: true, protocol: 'data:' }, + { host: undefined, allow: false, protocol: undefined }, // Default action is to deny! + ], + }), + }), + zoom: schema.number({ defaultValue: 2 }), + viewport: schema.object({ + width: schema.number({ defaultValue: 1950 }), + height: schema.number({ defaultValue: 1200 }), + }), + loadDelay: schema.number({ + defaultValue: moment.duration(3, 's').asMilliseconds(), + }), // TODO: use schema.duration + browser: schema.object({ + autoDownload: schema.conditional( + schema.contextRef('dist'), + true, + schema.boolean({ defaultValue: false }), + schema.boolean({ defaultValue: true }) + ), + chromium: schema.object({ + inspect: schema.conditional( + schema.contextRef('dist'), + true, + schema.boolean({ defaultValue: false }), + schema.maybe(schema.never()) + ), + disableSandbox: schema.boolean({ defaultValue: false }), + proxy: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + server: schema.conditional( + schema.siblingRef('enabled'), + true, + schema.uri({ scheme: ['http', 'https'] }), + schema.maybe(schema.never()) + ), + bypass: schema.conditional( + schema.siblingRef('enabled'), + true, + schema.arrayOf(schema.string({ hostname: true })), + schema.maybe(schema.never()) + ), + }), + userDataDir: schema.maybe(schema.string()), // FIXME unused? + }), + type: schema.string({ defaultValue: 'chromium' }), + }), + maxAttempts: schema.conditional( + schema.contextRef('dist'), + true, + schema.number({ defaultValue: 3 }), + schema.number({ defaultValue: 1 }) + ), +}); + +const CsvSchema = schema.object({ + checkForFormulas: schema.boolean({ defaultValue: true }), + enablePanelActionDownload: schema.boolean({ defaultValue: true }), + maxSizeBytes: schema.number({ + defaultValue: 1024 * 1024 * 10, // 10MB + }), // TODO: use schema.byteSize + scroll: schema.object({ + duration: schema.string({ + defaultValue: '30s', + validate(value) { + if (!/^[0-9]+(d|h|m|s|ms|micros|nanos)$/.test(value)) { + return 'must be a duration string'; + } + }, + }), + size: schema.number({ defaultValue: 500 }), + }), +}); + +const EncryptionKeySchema = schema.conditional( + schema.contextRef('dist'), + true, + schema.maybe(schema.string({ minLength: 32 })), + schema.string({ minLength: 32, defaultValue: 'a'.repeat(32) }) +); + +const RolesSchema = schema.object({ + allow: schema.arrayOf(schema.string(), { defaultValue: ['reporting_user'] }), +}); + +const IndexSchema = schema.string({ defaultValue: '.reporting' }); + +const PollSchema = schema.object({ + jobCompletionNotifier: schema.object({ + interval: schema.number({ + defaultValue: moment.duration(10, 's').asMilliseconds(), + }), // TODO: use schema.duration + intervalErrorMultiplier: schema.number({ defaultValue: 5 }), + }), + jobsRefresh: schema.object({ + interval: schema.number({ + defaultValue: moment.duration(5, 's').asMilliseconds(), + }), // TODO: use schema.duration + intervalErrorMultiplier: schema.number({ defaultValue: 5 }), + }), +}); + +export const ConfigSchema = schema.object({ + kibanaServer: KibanaServerSchema, + queue: QueueSchema, + capture: CaptureSchema, + csv: CsvSchema, + encryptionKey: EncryptionKeySchema, + roles: RolesSchema, + index: IndexSchema, + poll: PollSchema, +}); + +export type ConfigType = TypeOf; diff --git a/x-pack/plugins/reporting/server/index.ts b/x-pack/plugins/reporting/server/index.ts new file mode 100644 index 0000000000000..2b1844cf2e10e --- /dev/null +++ b/x-pack/plugins/reporting/server/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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { PluginInitializerContext } from 'src/core/server'; +import { ReportingPlugin } from './plugin'; + +export { config, ConfigSchema } from './config'; +export { ConfigType, PluginsSetup } from './plugin'; + +export const plugin = (initializerContext: PluginInitializerContext) => + new ReportingPlugin(initializerContext); diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts new file mode 100644 index 0000000000000..53d821cffbb1f --- /dev/null +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Observable } from 'rxjs'; +import { first } from 'rxjs/operators'; +import { CoreSetup, Logger, Plugin, PluginInitializerContext } from '../../../../src/core/server'; +import { ConfigType, createConfig$ } from './config'; + +export interface PluginsSetup { + /** @deprecated */ + __legacy: { + config$: Observable; + }; +} + +export class ReportingPlugin implements Plugin { + private readonly log: Logger; + + constructor(private readonly initializerContext: PluginInitializerContext) { + this.log = this.initializerContext.logger.get(); + } + + public async setup(core: CoreSetup): Promise { + return { + __legacy: { + config$: createConfig$(core, this.initializerContext, this.log).pipe(first()), + }, + }; + } + + public start() {} + public stop() {} +} + +export { ConfigType }; From 669a82d907898bcd90bdc5b9bbd4ffd5c280e9a2 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 6 Apr 2020 13:32:37 -0700 Subject: [PATCH 02/27] fix translations json --- x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 2 files changed, 2 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 023a97274b957..8d4506ab4e208 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -12488,7 +12488,6 @@ "xpack.reporting.screenCapturePanelContent.optimizeForPrintingLabel": "印刷用に最適化", "xpack.reporting.selfCheck.ok": "レポートプラグイン自己チェックOK!", "xpack.reporting.selfCheck.warning": "レポートプラグイン自己チェックで警告が発生しました: {err}", - "xpack.reporting.selfCheckEncryptionKey.warning": "{setting}のランダムキーを生成しています。保留中のレポートの再開が失敗しないように、kibana.ymlで{setting}を設定してください", "xpack.reporting.shareContextMenu.csvReportsButtonLabel": "CSV レポート", "xpack.reporting.shareContextMenu.pdfReportsButtonLabel": "PDF レポート", "xpack.reporting.shareContextMenu.pngReportsButtonLabel": "PNG レポート", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b359014e95e70..9d79e3ef5a257 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -12492,7 +12492,6 @@ "xpack.reporting.screenCapturePanelContent.optimizeForPrintingLabel": "打印优化", "xpack.reporting.selfCheck.ok": "Reporting 插件自检正常!", "xpack.reporting.selfCheck.warning": "Reporting 插件自检生成警告:{err}", - "xpack.reporting.selfCheckEncryptionKey.warning": "正在为 {setting} 生成随机密钥。要防止待处理报告在重新启动时失败,请在 kibana.yml 中设置 {setting}", "xpack.reporting.shareContextMenu.csvReportsButtonLabel": "CSV 报告", "xpack.reporting.shareContextMenu.pdfReportsButtonLabel": "PDF 报告", "xpack.reporting.shareContextMenu.pngReportsButtonLabel": "PNG 报告", From f659f0900ae9ee16360f56dff54a065b55768402 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 11:30:36 -0700 Subject: [PATCH 03/27] add csv.useByteOrderMarkEncoding to schema --- x-pack/plugins/reporting/server/config/schema.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts index 0058b7a5096f0..ea050a1ab9320 100644 --- a/x-pack/plugins/reporting/server/config/schema.ts +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -119,6 +119,7 @@ const CsvSchema = schema.object({ maxSizeBytes: schema.number({ defaultValue: 1024 * 1024 * 10, // 10MB }), // TODO: use schema.byteSize + useByteOrderMarkEncoding: schema.boolean({ defaultValue: false }), scroll: schema.object({ duration: schema.string({ defaultValue: '30s', From bb90123b298bdf3429be4479c3468ef475969ddf Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 11:52:43 -0700 Subject: [PATCH 04/27] imports cleanup --- x-pack/plugins/reporting/server/config/index.test.ts | 2 +- x-pack/plugins/reporting/server/config/index.ts | 2 +- x-pack/plugins/reporting/server/plugin.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/index.test.ts b/x-pack/plugins/reporting/server/config/index.test.ts index 08fe2c5861311..5182c857fef79 100644 --- a/x-pack/plugins/reporting/server/config/index.test.ts +++ b/x-pack/plugins/reporting/server/config/index.test.ts @@ -5,7 +5,7 @@ */ import * as Rx from 'rxjs'; -import { CoreSetup, Logger, PluginInitializerContext } from '../../../../../src/core/server'; +import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; import { createConfig$ } from './'; interface KibanaServer { diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index bc28e962ed011..463b9bf596062 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -9,7 +9,7 @@ import { TypeOf } from '@kbn/config-schema'; import crypto from 'crypto'; import { map } from 'rxjs/operators'; import { PluginConfigDescriptor } from 'kibana/server'; -import { CoreSetup, Logger, PluginInitializerContext } from '../../../../../src/core/server'; +import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; import { ConfigSchema, ConfigType } from './schema'; /* diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index 53d821cffbb1f..905ed2b237c86 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -6,7 +6,7 @@ import { Observable } from 'rxjs'; import { first } from 'rxjs/operators'; -import { CoreSetup, Logger, Plugin, PluginInitializerContext } from '../../../../src/core/server'; +import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'src/core/server'; import { ConfigType, createConfig$ } from './config'; export interface PluginsSetup { From b09ff8aad4056eb522bc1295144ffd5ab4d45b6e Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 12:30:44 -0700 Subject: [PATCH 05/27] restore "get default chromium sandbox disabled" functionality --- .../default_chromium_sandbox_disabled.test.ts | 38 +++++++++++++++++ .../default_chromium_sandbox_disabled.ts | 42 +++++++++++++++++++ .../plugins/reporting/server/config/index.ts | 20 ++++++++- .../plugins/reporting/server/config/schema.ts | 2 +- 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.test.ts create mode 100644 x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts diff --git a/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.test.ts b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.test.ts new file mode 100644 index 0000000000000..5c6129b0974d2 --- /dev/null +++ b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.test.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +jest.mock('getos', () => { + return jest.fn(); +}); + +import { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; +import getos from 'getos'; + +interface TestObject { + os: string; + dist?: string; + release?: string; +} + +function defaultTest(os: TestObject, expectedDefault: boolean) { + test(`${expectedDefault ? 'disabled' : 'enabled'} on ${JSON.stringify(os)}`, async () => { + (getos as jest.Mock).mockImplementation(cb => cb(null, os)); + const actualDefault = await getDefaultChromiumSandboxDisabled(); + expect(actualDefault).toBe(expectedDefault); + }); +} + +defaultTest({ os: 'win32' }, false); +defaultTest({ os: 'darwin' }, false); +defaultTest({ os: 'linux', dist: 'Centos', release: '7.0' }, true); +defaultTest({ os: 'linux', dist: 'Red Hat Linux', release: '7.0' }, true); +defaultTest({ os: 'linux', dist: 'Ubuntu Linux', release: '14.04' }, false); +defaultTest({ os: 'linux', dist: 'Ubuntu Linux', release: '16.04' }, false); +defaultTest({ os: 'linux', dist: 'SUSE Linux', release: '11' }, false); +defaultTest({ os: 'linux', dist: 'SUSE Linux', release: '12' }, false); +defaultTest({ os: 'linux', dist: 'SUSE Linux', release: '42.0' }, false); +defaultTest({ os: 'linux', dist: 'Debian', release: '8' }, true); +defaultTest({ os: 'linux', dist: 'Debian', release: '9' }, true); diff --git a/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts new file mode 100644 index 0000000000000..a21a4b33722ff --- /dev/null +++ b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import getosSync from 'getos'; +import { promisify } from 'util'; + +const getos = promisify(getosSync); + +const distroSupportsUnprivilegedUsernamespaces = (distro: string) => { + // Debian 7 and 8 don't support usernamespaces by default + // this should be reevaluated when Debian 9 is available + if (distro.toLowerCase() === 'debian') { + return false; + } + + // Starting at CentOS 7.2 usernamespaces are in the kernel + // but they must be explicitly enabled. This should be reevaluated + // once CentOS 7.5+ is available + if (distro.toLowerCase() === 'centos') { + return false; + } + + // Tested on OracleLinux 7.4 (which returns 'red hat linux' for distro) and sandboxing failed. + if (distro.toLowerCase() === 'red hat linux') { + return false; + } + + return true; +}; + +export async function getDefaultChromiumSandboxDisabled() { + const os = await getos(); + + if (os.os === 'linux' && !distroSupportsUnprivilegedUsernamespaces(os.dist)) { + return true; + } else { + return false; + } +} diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index 463b9bf596062..a8e0ae32a1190 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -7,13 +7,17 @@ import { i18n } from '@kbn/i18n/'; import { TypeOf } from '@kbn/config-schema'; import crypto from 'crypto'; -import { map } from 'rxjs/operators'; import { PluginConfigDescriptor } from 'kibana/server'; +import { map, mergeMap } from 'rxjs/operators'; import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; +import { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; import { ConfigSchema, ConfigType } from './schema'; /* * Set up dynamic config defaults + * - xpack.reporting.encryptionKey + * - xpack.kibanaServer + * - xpack.capture.browser.chromium.disableSandbox */ export function createConfig$(core: CoreSetup, context: PluginInitializerContext, logger: Logger) { return context.config.create>().pipe( @@ -70,6 +74,20 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext protocol: kibanaServerProtocol, }, }; + }), + mergeMap(async config => { + // if the disableSandbox is unset / undefined, give it a default depending on the OS + if (config.capture.browser.chromium.disableSandbox != null) { + // disableSandbox was set + return config; + } + + // disableSandbox was not set: apply default for OS + return Object.assign(config, { + capture: { + browser: { chromium: { disableSandbox: await getDefaultChromiumSandboxDisabled() } }, + }, + }); }) ); } diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts index ea050a1ab9320..c9347e5fef28d 100644 --- a/x-pack/plugins/reporting/server/config/schema.ts +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -85,7 +85,7 @@ const CaptureSchema = schema.object({ schema.boolean({ defaultValue: false }), schema.maybe(schema.never()) ), - disableSandbox: schema.boolean({ defaultValue: false }), + disableSandbox: schema.maybe(schema.boolean()), // leave this unset and determine the default at runtime proxy: schema.object({ enabled: schema.boolean({ defaultValue: false }), server: schema.conditional( From 04c30abc748629b454f5dde5522e55ad18888239 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 12:55:57 -0700 Subject: [PATCH 06/27] integrate getDefaultChromiumSandboxDisabled --- .../default_chromium_sandbox_disabled.ts | 11 ++++-- .../plugins/reporting/server/config/index.ts | 34 ++++++++++++++++--- .../reporting/server/config/schema.test.ts | 8 +++-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts index a21a4b33722ff..4c24a0e7cd794 100644 --- a/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts +++ b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts @@ -31,12 +31,17 @@ const distroSupportsUnprivilegedUsernamespaces = (distro: string) => { return true; }; -export async function getDefaultChromiumSandboxDisabled() { +interface OsSummary { + disableSandbox: boolean; + os: { os: string; dist: string; release: string }; +} + +export async function getDefaultChromiumSandboxDisabled(): Promise { const os = await getos(); if (os.os === 'linux' && !distroSupportsUnprivilegedUsernamespaces(os.dist)) { - return true; + return { os, disableSandbox: true }; } else { - return false; + return { os: { ...os, dist: 'unknown', release: 'unknown' }, disableSandbox: false }; } } diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index a8e0ae32a1190..44e73af668b66 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -46,7 +46,7 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext logger.warn( i18n.translate('xpack.reporting.serverConfig.invalidServerHostname', { defaultMessage: - `Found 'server.host: "0" in Kibana configuration. This is incompatible with Reporting. ` + + `Found 'server.host: "0"' in Kibana configuration. This is incompatible with Reporting. ` + `To enable Reporting to work, '{configKey}: 0.0.0.0' is being automatically to the configuration. ` + `You can change the setting to 'server.host: 0.0.0.0' or add '{configKey}: 0.0.0.0' in kibana.yml to prevent this message.`, values: { configKey: 'xpack.reporting.kibanaServer.hostname' }, @@ -76,16 +76,42 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext }; }), mergeMap(async config => { - // if the disableSandbox is unset / undefined, give it a default depending on the OS if (config.capture.browser.chromium.disableSandbox != null) { - // disableSandbox was set + // disableSandbox was set by user return config; } // disableSandbox was not set: apply default for OS + const { os, disableSandbox } = await getDefaultChromiumSandboxDisabled(); + logger.debug( + i18n.translate(`xpack.reporting.serverConfig.osDetected`, { + defaultMessage: + 'Running on OS: "{osName}", distribution: "{dist}", release: "${release}"', + values: { osName: os.os, dist: os.dist, release: os.release }, + }) + ); + if (!disableSandbox) { + logger.warn( + i18n.translate('xpack.reporting.serverConfig.sandboxDisabled', { + defaultMessage: `Setting '{configKey}: false' in Reporting config: not supported for {osName}`, + values: { + configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', + osName: `${os.os}/${os.dist}`, + }, + }) + ); + } return Object.assign(config, { + ...config, capture: { - browser: { chromium: { disableSandbox: await getDefaultChromiumSandboxDisabled() } }, + ...config.capture, + browser: { + ...config.capture.browser, + chromium: { + ...config.capture.browser.chromium, + disableSandbox, + }, + }, }, }); }) diff --git a/x-pack/plugins/reporting/server/config/schema.test.ts b/x-pack/plugins/reporting/server/config/schema.test.ts index d8fe6d1ff084a..0ccf8fe780cbb 100644 --- a/x-pack/plugins/reporting/server/config/schema.test.ts +++ b/x-pack/plugins/reporting/server/config/schema.test.ts @@ -12,7 +12,7 @@ describe('Reporting Config Schema', () => { capture: { browser: { autoDownload: true, - chromium: { disableSandbox: false, proxy: { enabled: false } }, + chromium: { disableSandbox: expect.any(Boolean), proxy: { enabled: false } }, type: 'chromium', }, loadDelay: 3000, @@ -59,7 +59,11 @@ describe('Reporting Config Schema', () => { capture: { browser: { autoDownload: false, - chromium: { disableSandbox: false, inspect: false, proxy: { enabled: false } }, + chromium: { + disableSandbox: expect.any(Boolean), + inspect: false, + proxy: { enabled: false }, + }, type: 'chromium', }, loadDelay: 3000, From 0591c0c1c67904e973d10c24e551a7a3c88a2b7f Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 13:53:20 -0700 Subject: [PATCH 07/27] fix tests --- .../server/config/default_chromium_sandbox_disabled.test.ts | 2 +- x-pack/plugins/reporting/server/config/schema.test.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.test.ts b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.test.ts index 5c6129b0974d2..307c96bb34909 100644 --- a/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.test.ts +++ b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.test.ts @@ -21,7 +21,7 @@ function defaultTest(os: TestObject, expectedDefault: boolean) { test(`${expectedDefault ? 'disabled' : 'enabled'} on ${JSON.stringify(os)}`, async () => { (getos as jest.Mock).mockImplementation(cb => cb(null, os)); const actualDefault = await getDefaultChromiumSandboxDisabled(); - expect(actualDefault).toBe(expectedDefault); + expect(actualDefault.disableSandbox).toBe(expectedDefault); }); } diff --git a/x-pack/plugins/reporting/server/config/schema.test.ts b/x-pack/plugins/reporting/server/config/schema.test.ts index 0ccf8fe780cbb..117ef06c93cd2 100644 --- a/x-pack/plugins/reporting/server/config/schema.test.ts +++ b/x-pack/plugins/reporting/server/config/schema.test.ts @@ -12,7 +12,7 @@ describe('Reporting Config Schema', () => { capture: { browser: { autoDownload: true, - chromium: { disableSandbox: expect.any(Boolean), proxy: { enabled: false } }, + chromium: { proxy: { enabled: false } }, type: 'chromium', }, loadDelay: 3000, @@ -60,7 +60,6 @@ describe('Reporting Config Schema', () => { browser: { autoDownload: false, chromium: { - disableSandbox: expect.any(Boolean), inspect: false, proxy: { enabled: false }, }, From e423723584c907f286332ca8cd2732ca8189220b Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 14:12:32 -0700 Subject: [PATCH 08/27] --wip-- [skip ci] --- .../reporting/server/config/schema.test.ts | 17 +++++++++++++++++ .../plugins/reporting/server/config/schema.ts | 10 +++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/schema.test.ts b/x-pack/plugins/reporting/server/config/schema.test.ts index 117ef06c93cd2..74bb2c9287ff5 100644 --- a/x-pack/plugins/reporting/server/config/schema.test.ts +++ b/x-pack/plugins/reporting/server/config/schema.test.ts @@ -54,6 +54,7 @@ describe('Reporting Config Schema', () => { roles: { allow: ['reporting_user'] }, }); }); + it(`context {"dev":false,"dist":true} produces correct config`, () => { expect(ConfigSchema.validate({}, { dev: false, dist: true })).toMatchObject({ capture: { @@ -103,4 +104,20 @@ describe('Reporting Config Schema', () => { roles: { allow: ['reporting_user'] }, }); }); + + it(`allows optional settings`, () => { + expect( + ConfigSchema.validate({ encryptionKey: 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' }) + .encryptionKey + ).toBe('qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); + + expect( + ConfigSchema.validate({ capture: { browser: { chromium: { disableSandbox: true } } } }) + .capture.browser.chromium + ).toMatchObject({ disableSandbox: true, proxy: { enabled: false } }); + + expect( + ConfigSchema.validate({ kibanaServer: { hostname: 'Frodo' } }).kibanaServer + ).toMatchObject({ hostname: 'Frodo' }); + }); }); diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts index c9347e5fef28d..280083f9af936 100644 --- a/x-pack/plugins/reporting/server/config/schema.ts +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -7,8 +7,13 @@ import { schema, TypeOf } from '@kbn/config-schema'; import moment from 'moment'; +/* + * NOTE dynamic defaults are processed in the createConfig$ function + */ + const KibanaServerSchema = schema.object({ hostname: schema.maybe( + // default value is dynamic schema.string({ validate(value) { if (value === '0') { @@ -85,7 +90,7 @@ const CaptureSchema = schema.object({ schema.boolean({ defaultValue: false }), schema.maybe(schema.never()) ), - disableSandbox: schema.maybe(schema.boolean()), // leave this unset and determine the default at runtime + disableSandbox: schema.maybe(schema.boolean()), // default value is dynamic proxy: schema.object({ enabled: schema.boolean({ defaultValue: false }), server: schema.conditional( @@ -101,7 +106,6 @@ const CaptureSchema = schema.object({ schema.maybe(schema.never()) ), }), - userDataDir: schema.maybe(schema.string()), // FIXME unused? }), type: schema.string({ defaultValue: 'chromium' }), }), @@ -136,7 +140,7 @@ const CsvSchema = schema.object({ const EncryptionKeySchema = schema.conditional( schema.contextRef('dist'), true, - schema.maybe(schema.string({ minLength: 32 })), + schema.maybe(schema.string({ minLength: 32 })), // default value is dynamic schema.string({ minLength: 32, defaultValue: 'a'.repeat(32) }) ); From 89bdd617aece68b91fca7dcfd0ade8b57f7afb55 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 14:18:13 -0700 Subject: [PATCH 09/27] add more schema tests --- x-pack/plugins/reporting/server/config/schema.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/x-pack/plugins/reporting/server/config/schema.test.ts b/x-pack/plugins/reporting/server/config/schema.test.ts index 74bb2c9287ff5..41285c2bfa133 100644 --- a/x-pack/plugins/reporting/server/config/schema.test.ts +++ b/x-pack/plugins/reporting/server/config/schema.test.ts @@ -106,18 +106,29 @@ describe('Reporting Config Schema', () => { }); it(`allows optional settings`, () => { + // encryption key expect( ConfigSchema.validate({ encryptionKey: 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' }) .encryptionKey ).toBe('qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); + // disableSandbox expect( ConfigSchema.validate({ capture: { browser: { chromium: { disableSandbox: true } } } }) .capture.browser.chromium ).toMatchObject({ disableSandbox: true, proxy: { enabled: false } }); + // kibanaServer expect( ConfigSchema.validate({ kibanaServer: { hostname: 'Frodo' } }).kibanaServer ).toMatchObject({ hostname: 'Frodo' }); }); + + it(`logs the proper validation messages`, () => { + // kibanaServer + const throwValidationErr = () => ConfigSchema.validate({ kibanaServer: { hostname: '0' } }); + expect(throwValidationErr).toThrowError( + `[kibanaServer.hostname]: must not be "0" for the headless browser to correctly resolve the host` + ); + }); }); From 3e92310f160d82503a1d8a47b1cea78e3ce1d6d9 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 14:28:00 -0700 Subject: [PATCH 10/27] diff prettiness --- x-pack/legacy/plugins/reporting/server/config/index.ts | 3 +-- .../reporting/server/lib/esqueue/helpers/index_timestamp.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/reporting/server/config/index.ts b/x-pack/legacy/plugins/reporting/server/config/index.ts index 0ad665864228d..c6b915be3a94a 100644 --- a/x-pack/legacy/plugins/reporting/server/config/index.ts +++ b/x-pack/legacy/plugins/reporting/server/config/index.ts @@ -8,6 +8,7 @@ import { Legacy } from 'kibana'; import { CoreSetup } from 'src/core/server'; import { get } from 'lodash'; import { ConfigType as ReportingConfigType } from '../../../../../plugins/reporting/server'; +export { ReportingConfigType }; // make config.get() aware of the value type it returns interface Config { @@ -84,5 +85,3 @@ export const buildConfig = ( }, }; }; - -export { ReportingConfigType }; diff --git a/x-pack/legacy/plugins/reporting/server/lib/esqueue/helpers/index_timestamp.js b/x-pack/legacy/plugins/reporting/server/lib/esqueue/helpers/index_timestamp.js index 8e4047e2f22e5..ceb4ef43b2d9d 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/esqueue/helpers/index_timestamp.js +++ b/x-pack/legacy/plugins/reporting/server/lib/esqueue/helpers/index_timestamp.js @@ -8,7 +8,7 @@ import moment from 'moment'; export const intervals = ['year', 'month', 'week', 'day', 'hour', 'minute']; -// TODO: remove this helper by using `schema.duration` objects in the reporting config schema +// TODO: This helper function can be removed by using `schema.duration` objects in the reporting config schema export function indexTimestamp(intervalStr, separator = '-') { if (separator.match(/[a-z]/i)) throw new Error('Interval separator can not be a letter'); From 31237351bdce2ebb7650f7c1df3fc3c90cd4cd44 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 14:31:57 -0700 Subject: [PATCH 11/27] trash legacy files that moved to NP --- .../default_chromium_sandbox_disabled.test.js | 32 -------------- .../default_chromium_sandbox_disabled.ts | 42 ------------------- .../plugins/reporting/server/config/index.ts | 4 +- 3 files changed, 2 insertions(+), 76 deletions(-) delete mode 100644 x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.test.js delete mode 100644 x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.ts diff --git a/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.test.js b/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.test.js deleted file mode 100644 index a022506f9e2da..0000000000000 --- a/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.test.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -jest.mock('getos', () => { - return jest.fn(); -}); - -import { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; -import getos from 'getos'; - -function defaultTest(os, expectedDefault) { - test(`${expectedDefault ? 'disabled' : 'enabled'} on ${JSON.stringify(os)}`, async () => { - getos.mockImplementation(cb => cb(null, os)); - const actualDefault = await getDefaultChromiumSandboxDisabled(); - expect(actualDefault).toBe(expectedDefault); - }); -} - -defaultTest({ os: 'win32' }, false); -defaultTest({ os: 'darwin' }, false); -defaultTest({ os: 'linux', dist: 'Centos', release: '7.0' }, true); -defaultTest({ os: 'linux', dist: 'Red Hat Linux', release: '7.0' }, true); -defaultTest({ os: 'linux', dist: 'Ubuntu Linux', release: '14.04' }, false); -defaultTest({ os: 'linux', dist: 'Ubuntu Linux', release: '16.04' }, false); -defaultTest({ os: 'linux', dist: 'SUSE Linux', release: '11' }, false); -defaultTest({ os: 'linux', dist: 'SUSE Linux', release: '12' }, false); -defaultTest({ os: 'linux', dist: 'SUSE Linux', release: '42.0' }, false); -defaultTest({ os: 'linux', dist: 'Debian', release: '8' }, true); -defaultTest({ os: 'linux', dist: 'Debian', release: '9' }, true); diff --git a/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.ts b/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.ts deleted file mode 100644 index a21a4b33722ff..0000000000000 --- a/x-pack/legacy/plugins/reporting/server/browsers/default_chromium_sandbox_disabled.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import getosSync from 'getos'; -import { promisify } from 'util'; - -const getos = promisify(getosSync); - -const distroSupportsUnprivilegedUsernamespaces = (distro: string) => { - // Debian 7 and 8 don't support usernamespaces by default - // this should be reevaluated when Debian 9 is available - if (distro.toLowerCase() === 'debian') { - return false; - } - - // Starting at CentOS 7.2 usernamespaces are in the kernel - // but they must be explicitly enabled. This should be reevaluated - // once CentOS 7.5+ is available - if (distro.toLowerCase() === 'centos') { - return false; - } - - // Tested on OracleLinux 7.4 (which returns 'red hat linux' for distro) and sandboxing failed. - if (distro.toLowerCase() === 'red hat linux') { - return false; - } - - return true; -}; - -export async function getDefaultChromiumSandboxDisabled() { - const os = await getos(); - - if (os.os === 'linux' && !distroSupportsUnprivilegedUsernamespaces(os.dist)) { - return true; - } else { - return false; - } -} diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index 44e73af668b66..c556ee0472d4a 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -15,9 +15,9 @@ import { ConfigSchema, ConfigType } from './schema'; /* * Set up dynamic config defaults - * - xpack.reporting.encryptionKey - * - xpack.kibanaServer * - xpack.capture.browser.chromium.disableSandbox + * - xpack.kibanaServer + * - xpack.reporting.encryptionKey */ export function createConfig$(core: CoreSetup, context: PluginInitializerContext, logger: Logger) { return context.config.create>().pipe( From 96f3a7e34e098fa3621406fd56bbf3860561e251 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 15:19:26 -0700 Subject: [PATCH 12/27] create_config tests --- .../reporting/server/config/index.test.ts | 58 +++++++++++++++---- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/index.test.ts b/x-pack/plugins/reporting/server/config/index.test.ts index 5182c857fef79..22779b73bc5c1 100644 --- a/x-pack/plugins/reporting/server/config/index.test.ts +++ b/x-pack/plugins/reporting/server/config/index.test.ts @@ -6,6 +6,7 @@ import * as Rx from 'rxjs'; import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; +import { ConfigType as ReportingConfigType } from './schema'; import { createConfig$ } from './'; interface KibanaServer { @@ -13,18 +14,21 @@ interface KibanaServer { port?: number; protocol?: string; } -interface ReportingKibanaServer { - hostname?: string; - port?: number; - protocol?: string; -} const makeMockInitContext = (config: { + capture?: Partial; encryptionKey?: string; - kibanaServer: ReportingKibanaServer; + kibanaServer: Partial; }): PluginInitializerContext => ({ - config: { create: () => Rx.of(config) }, + config: { + create: () => + Rx.of({ + ...config, + capture: config.capture || { browser: { chromium: { disableSandbox: false } } }, + kibanaServer: config.kibanaServer || {}, + }), + }, } as PluginInitializerContext); const makeMockCoreSetup = (serverInfo: KibanaServer): CoreSetup => @@ -40,7 +44,7 @@ describe('Reporting server createConfig$', () => { mockInitContext = makeMockInitContext({ kibanaServer: {}, }); - mockLogger = ({ warn: jest.fn() } as unknown) as Logger; + mockLogger = ({ warn: jest.fn(), debug: jest.fn() } as unknown) as Logger; }); afterEach(() => { @@ -64,7 +68,7 @@ describe('Reporting server createConfig$', () => { ]); }); - it('uses the encryption key', async () => { + it('uses the user-provided encryption key', async () => { mockInitContext = makeMockInitContext({ encryptionKey: 'iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii', kibanaServer: {}, @@ -75,7 +79,7 @@ describe('Reporting server createConfig$', () => { expect((mockLogger.warn as any).mock.calls.length).toBe(0); }); - it('uses the encryption key, reporting kibanaServer settings to override server info', async () => { + it('uses the user-provided encryption key, reporting kibanaServer settings to override server info', async () => { mockInitContext = makeMockInitContext({ encryptionKey: 'iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii', kibanaServer: { @@ -88,6 +92,13 @@ describe('Reporting server createConfig$', () => { expect(result).toMatchInlineSnapshot(` Object { + "capture": Object { + "browser": Object { + "chromium": Object { + "disableSandbox": false, + }, + }, + }, "encryptionKey": "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii", "kibanaServer": Object { "hostname": "reportingHost", @@ -115,8 +126,33 @@ describe('Reporting server createConfig$', () => { `); expect((mockLogger.warn as any).mock.calls.length).toBe(1); expect((mockLogger.warn as any).mock.calls[0]).toMatchObject([ - `Found 'server.host: \"0\" in Kibana configuration. This is incompatible with Reporting. To enable Reporting to work, 'xpack.reporting.kibanaServer.hostname: 0.0.0.0' is being automatically ` + + `Found 'server.host: \"0\"' in Kibana configuration. This is incompatible with Reporting. To enable Reporting to work, 'xpack.reporting.kibanaServer.hostname: 0.0.0.0' is being automatically ` + `to the configuration. You can change the setting to 'server.host: 0.0.0.0' or add 'xpack.reporting.kibanaServer.hostname: 0.0.0.0' in kibana.yml to prevent this message.`, ]); }); + + it('uses user-provided disableSandbox: false', async () => { + mockInitContext = makeMockInitContext({ + capture: { browser: { chromium: { disableSandbox: false } } }, + } as ReportingConfigType); + const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + expect(result.capture.browser.chromium).toMatchObject({ disableSandbox: false }); + }); + + it('uses user-provided disableSandbox: true', async () => { + mockInitContext = makeMockInitContext({ + capture: { browser: { chromium: { disableSandbox: true } } }, + } as ReportingConfigType); + const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + expect(result.capture.browser.chromium).toMatchObject({ disableSandbox: true }); + }); + + it('provides a default for disableSandbox', async () => { + mockInitContext = makeMockInitContext({ + encryptionKey: '888888888888888888888888888888888', + } as ReportingConfigType); + const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + expect(result.capture.browser.chromium).toMatchObject({ disableSandbox: false }); + expect((mockLogger.warn as any).mock.calls.length).toBe(0); + }); }); From 02b91b8d42e9bbf4dfe8f03e70fe1d5c0c1d29fe Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 15:25:05 -0700 Subject: [PATCH 13/27] Hoist create_config --- .../{index.test.ts => create_config.test.ts} | 2 +- .../reporting/server/config/create_config.ts | 111 ++++++++++++++++++ .../plugins/reporting/server/config/index.ts | 111 +----------------- 3 files changed, 113 insertions(+), 111 deletions(-) rename x-pack/plugins/reporting/server/config/{index.test.ts => create_config.test.ts} (99%) create mode 100644 x-pack/plugins/reporting/server/config/create_config.ts diff --git a/x-pack/plugins/reporting/server/config/index.test.ts b/x-pack/plugins/reporting/server/config/create_config.test.ts similarity index 99% rename from x-pack/plugins/reporting/server/config/index.test.ts rename to x-pack/plugins/reporting/server/config/create_config.test.ts index 22779b73bc5c1..d832abccd476b 100644 --- a/x-pack/plugins/reporting/server/config/index.test.ts +++ b/x-pack/plugins/reporting/server/config/create_config.test.ts @@ -7,7 +7,7 @@ import * as Rx from 'rxjs'; import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; import { ConfigType as ReportingConfigType } from './schema'; -import { createConfig$ } from './'; +import { createConfig$ } from './create_config'; interface KibanaServer { host?: string; diff --git a/x-pack/plugins/reporting/server/config/create_config.ts b/x-pack/plugins/reporting/server/config/create_config.ts new file mode 100644 index 0000000000000..e0a2626d9ce5a --- /dev/null +++ b/x-pack/plugins/reporting/server/config/create_config.ts @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n/'; +import { TypeOf } from '@kbn/config-schema'; +import crypto from 'crypto'; +import { map, mergeMap } from 'rxjs/operators'; +import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; +import { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; +import { ConfigSchema } from './schema'; +/* + * Set up dynamic config defaults + * - xpack.capture.browser.chromium.disableSandbox + * - xpack.kibanaServer + * - xpack.reporting.encryptionKey + */ +export function createConfig$(core: CoreSetup, context: PluginInitializerContext, logger: Logger) { + return context.config.create>().pipe( + map(config => { + // encryption key + let encryptionKey = config.encryptionKey; + if (encryptionKey === undefined) { + logger.warn( + i18n.translate('xpack.reporting.serverConfig.randomEncryptionKey', { + defaultMessage: + 'Generating a random key for xpack.reporting.encryptionKey. To prevent sessions from being invalidated on ' + + 'restart, please set xpack.reporting.encryptionKey in kibana.yml', + }) + ); + encryptionKey = crypto.randomBytes(16).toString('hex'); + } + const { kibanaServer: reportingServer } = config; + const serverInfo = core.http.getServerInfo(); + // kibanaServer.hostname, default to server.host, don't allow "0" + let kibanaServerHostname = reportingServer.hostname + ? reportingServer.hostname + : serverInfo.host; + if (kibanaServerHostname === '0') { + logger.warn( + i18n.translate('xpack.reporting.serverConfig.invalidServerHostname', { + defaultMessage: + `Found 'server.host: "0"' in Kibana configuration. This is incompatible with Reporting. ` + + `To enable Reporting to work, '{configKey}: 0.0.0.0' is being automatically to the configuration. ` + + `You can change the setting to 'server.host: 0.0.0.0' or add '{configKey}: 0.0.0.0' in kibana.yml to prevent this message.`, + values: { configKey: 'xpack.reporting.kibanaServer.hostname' }, + }) + ); + kibanaServerHostname = '0.0.0.0'; + } + // kibanaServer.port, default to server.port + const kibanaServerPort = reportingServer.port + ? reportingServer.port + : serverInfo.port; // prettier-ignore + // kibanaServer.protocol, default to server.protocol + const kibanaServerProtocol = reportingServer.protocol + ? reportingServer.protocol + : serverInfo.protocol; + return { + ...config, + encryptionKey, + kibanaServer: { + hostname: kibanaServerHostname, + port: kibanaServerPort, + protocol: kibanaServerProtocol, + }, + }; + }), + mergeMap(async config => { + if (config.capture.browser.chromium.disableSandbox != null) { + // disableSandbox was set by user + return config; + } + // disableSandbox was not set: apply default for OS + const { os, disableSandbox } = await getDefaultChromiumSandboxDisabled(); + logger.debug( + i18n.translate(`xpack.reporting.serverConfig.osDetected`, { + defaultMessage: + 'Running on OS: "{osName}", distribution: "{dist}", release: "${release}"', + values: { osName: os.os, dist: os.dist, release: os.release }, + }) + ); + if (!disableSandbox) { + logger.warn( + i18n.translate('xpack.reporting.serverConfig.sandboxDisabled', { + defaultMessage: `Setting '{configKey}: false' in Reporting config: not supported for {osName}`, + values: { + configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', + osName: `${os.os}/${os.dist}`, + }, + }) + ); + } + return Object.assign(config, { + ...config, + capture: { + ...config.capture, + browser: { + ...config.capture.browser, + chromium: { + ...config.capture.browser.chromium, + disableSandbox, + }, + }, + }, + }); + }) + ); +} diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index c556ee0472d4a..f0a0a093aa8c0 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -4,119 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { i18n } from '@kbn/i18n/'; -import { TypeOf } from '@kbn/config-schema'; -import crypto from 'crypto'; import { PluginConfigDescriptor } from 'kibana/server'; -import { map, mergeMap } from 'rxjs/operators'; -import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; -import { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; import { ConfigSchema, ConfigType } from './schema'; -/* - * Set up dynamic config defaults - * - xpack.capture.browser.chromium.disableSandbox - * - xpack.kibanaServer - * - xpack.reporting.encryptionKey - */ -export function createConfig$(core: CoreSetup, context: PluginInitializerContext, logger: Logger) { - return context.config.create>().pipe( - map(config => { - // encryption key - let encryptionKey = config.encryptionKey; - if (encryptionKey === undefined) { - logger.warn( - i18n.translate('xpack.reporting.serverConfig.randomEncryptionKey', { - defaultMessage: - 'Generating a random key for xpack.reporting.encryptionKey. To prevent sessions from being invalidated on ' + - 'restart, please set xpack.reporting.encryptionKey in kibana.yml', - }) - ); - encryptionKey = crypto.randomBytes(16).toString('hex'); - } - - const { kibanaServer: reportingServer } = config; - const serverInfo = core.http.getServerInfo(); - - // kibanaServer.hostname, default to server.host, don't allow "0" - let kibanaServerHostname = reportingServer.hostname - ? reportingServer.hostname - : serverInfo.host; - if (kibanaServerHostname === '0') { - logger.warn( - i18n.translate('xpack.reporting.serverConfig.invalidServerHostname', { - defaultMessage: - `Found 'server.host: "0"' in Kibana configuration. This is incompatible with Reporting. ` + - `To enable Reporting to work, '{configKey}: 0.0.0.0' is being automatically to the configuration. ` + - `You can change the setting to 'server.host: 0.0.0.0' or add '{configKey}: 0.0.0.0' in kibana.yml to prevent this message.`, - values: { configKey: 'xpack.reporting.kibanaServer.hostname' }, - }) - ); - kibanaServerHostname = '0.0.0.0'; - } - - // kibanaServer.port, default to server.port - const kibanaServerPort = reportingServer.port - ? reportingServer.port - : serverInfo.port; // prettier-ignore - - // kibanaServer.protocol, default to server.protocol - const kibanaServerProtocol = reportingServer.protocol - ? reportingServer.protocol - : serverInfo.protocol; - - return { - ...config, - encryptionKey, - kibanaServer: { - hostname: kibanaServerHostname, - port: kibanaServerPort, - protocol: kibanaServerProtocol, - }, - }; - }), - mergeMap(async config => { - if (config.capture.browser.chromium.disableSandbox != null) { - // disableSandbox was set by user - return config; - } - - // disableSandbox was not set: apply default for OS - const { os, disableSandbox } = await getDefaultChromiumSandboxDisabled(); - logger.debug( - i18n.translate(`xpack.reporting.serverConfig.osDetected`, { - defaultMessage: - 'Running on OS: "{osName}", distribution: "{dist}", release: "${release}"', - values: { osName: os.os, dist: os.dist, release: os.release }, - }) - ); - if (!disableSandbox) { - logger.warn( - i18n.translate('xpack.reporting.serverConfig.sandboxDisabled', { - defaultMessage: `Setting '{configKey}: false' in Reporting config: not supported for {osName}`, - values: { - configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', - osName: `${os.os}/${os.dist}`, - }, - }) - ); - } - return Object.assign(config, { - ...config, - capture: { - ...config.capture, - browser: { - ...config.capture.browser, - chromium: { - ...config.capture.browser.chromium, - disableSandbox, - }, - }, - }, - }); - }) - ); -} +export { createConfig$ } from './create_config'; export const config: PluginConfigDescriptor = { schema: ConfigSchema, From 5aab9642800555bfc268124947f15e01b26ca0f0 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 15:39:52 -0700 Subject: [PATCH 14/27] better disableSandbox tests --- .../reporting/server/config/create_config.test.ts | 9 ++++++++- x-pack/plugins/reporting/server/config/create_config.ts | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/create_config.test.ts b/x-pack/plugins/reporting/server/config/create_config.test.ts index d832abccd476b..b10a73d4dd000 100644 --- a/x-pack/plugins/reporting/server/config/create_config.test.ts +++ b/x-pack/plugins/reporting/server/config/create_config.test.ts @@ -133,18 +133,24 @@ describe('Reporting server createConfig$', () => { it('uses user-provided disableSandbox: false', async () => { mockInitContext = makeMockInitContext({ + encryptionKey: '888888888888888888888888888888888', capture: { browser: { chromium: { disableSandbox: false } } }, } as ReportingConfigType); const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + expect(result.capture.browser.chromium).toMatchObject({ disableSandbox: false }); + expect((mockLogger.warn as any).mock.calls.length).toBe(0); }); it('uses user-provided disableSandbox: true', async () => { mockInitContext = makeMockInitContext({ + encryptionKey: '888888888888888888888888888888888', capture: { browser: { chromium: { disableSandbox: true } } }, } as ReportingConfigType); const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); + expect(result.capture.browser.chromium).toMatchObject({ disableSandbox: true }); + expect((mockLogger.warn as any).mock.calls.length).toBe(0); }); it('provides a default for disableSandbox', async () => { @@ -152,7 +158,8 @@ describe('Reporting server createConfig$', () => { encryptionKey: '888888888888888888888888888888888', } as ReportingConfigType); const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); - expect(result.capture.browser.chromium).toMatchObject({ disableSandbox: false }); + + expect(result.capture.browser.chromium).toMatchObject({ disableSandbox: expect.any(Boolean) }); expect((mockLogger.warn as any).mock.calls.length).toBe(0); }); }); diff --git a/x-pack/plugins/reporting/server/config/create_config.ts b/x-pack/plugins/reporting/server/config/create_config.ts index e0a2626d9ce5a..a16281833a71a 100644 --- a/x-pack/plugins/reporting/server/config/create_config.ts +++ b/x-pack/plugins/reporting/server/config/create_config.ts @@ -11,6 +11,7 @@ import { map, mergeMap } from 'rxjs/operators'; import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; import { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; import { ConfigSchema } from './schema'; + /* * Set up dynamic config defaults * - xpack.capture.browser.chromium.disableSandbox @@ -73,6 +74,7 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext // disableSandbox was set by user return config; } + // disableSandbox was not set: apply default for OS const { os, disableSandbox } = await getDefaultChromiumSandboxDisabled(); logger.debug( @@ -82,9 +84,10 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext values: { osName: os.os, dist: os.dist, release: os.release }, }) ); - if (!disableSandbox) { + + if (disableSandbox) { logger.warn( - i18n.translate('xpack.reporting.serverConfig.sandboxDisabled', { + i18n.translate('xpack.reporting.serverConfig.autoSet.sandboxDisabled', { defaultMessage: `Setting '{configKey}: false' in Reporting config: not supported for {osName}`, values: { configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', @@ -93,6 +96,7 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext }) ); } + return Object.assign(config, { ...config, capture: { From b0ab462fc20ae9f93b9b0cb2e5259c578af4ce82 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 15:41:01 -0700 Subject: [PATCH 15/27] fix ts --- .../reporting/server/browsers/chromium/driver_factory/args.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/reporting/server/browsers/chromium/driver_factory/args.ts b/x-pack/legacy/plugins/reporting/server/browsers/chromium/driver_factory/args.ts index a2f7a1f3ad0da..928f3b8377809 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/chromium/driver_factory/args.ts +++ b/x-pack/legacy/plugins/reporting/server/browsers/chromium/driver_factory/args.ts @@ -10,7 +10,7 @@ type ViewportConfig = CaptureConfig['viewport']; type BrowserConfig = CaptureConfig['browser']['chromium']; interface LaunchArgs { - userDataDir: BrowserConfig['userDataDir']; + userDataDir: string; viewport: ViewportConfig; disableSandbox: BrowserConfig['disableSandbox']; proxy: BrowserConfig['proxy']; From 1fb5f5f5377deb6a0f01326c2e9651f0d5256d75 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 15:44:52 -0700 Subject: [PATCH 16/27] fix export --- x-pack/legacy/plugins/reporting/server/browsers/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/legacy/plugins/reporting/server/browsers/index.ts b/x-pack/legacy/plugins/reporting/server/browsers/index.ts index 1e42e2736962e..7f902c84308f6 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/index.ts +++ b/x-pack/legacy/plugins/reporting/server/browsers/index.ts @@ -8,7 +8,6 @@ import * as chromiumDefinition from './chromium'; export { ensureAllBrowsersDownloaded } from './download'; export { createBrowserDriverFactory } from './create_browser_driver_factory'; -export { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; export { HeadlessChromiumDriver } from './chromium/driver'; export { HeadlessChromiumDriverFactory } from './chromium/driver_factory'; From 619bcb420a38c702ba9e066c3e1bd29d006d95db Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 15:55:03 -0700 Subject: [PATCH 17/27] fix bad code --- x-pack/plugins/reporting/server/config/create_config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/create_config.ts b/x-pack/plugins/reporting/server/config/create_config.ts index a16281833a71a..98dcfb637b2b8 100644 --- a/x-pack/plugins/reporting/server/config/create_config.ts +++ b/x-pack/plugins/reporting/server/config/create_config.ts @@ -97,7 +97,7 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext ); } - return Object.assign(config, { + return { ...config, capture: { ...config.capture, @@ -109,7 +109,7 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext }, }, }, - }); + }; }) ); } From 1339af9bf6ba3303d434643249bcbbf8148d4b17 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 15:56:51 -0700 Subject: [PATCH 18/27] make comments better --- x-pack/plugins/reporting/server/config/schema.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts index 280083f9af936..67d70c1513c15 100644 --- a/x-pack/plugins/reporting/server/config/schema.ts +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -7,13 +7,8 @@ import { schema, TypeOf } from '@kbn/config-schema'; import moment from 'moment'; -/* - * NOTE dynamic defaults are processed in the createConfig$ function - */ - const KibanaServerSchema = schema.object({ hostname: schema.maybe( - // default value is dynamic schema.string({ validate(value) { if (value === '0') { @@ -33,7 +28,7 @@ const KibanaServerSchema = schema.object({ }, }) ), -}); +}); // default values are all dynamic in createConfig$ const QueueSchema = schema.object({ indexInterval: schema.string({ defaultValue: 'week' }), @@ -90,7 +85,7 @@ const CaptureSchema = schema.object({ schema.boolean({ defaultValue: false }), schema.maybe(schema.never()) ), - disableSandbox: schema.maybe(schema.boolean()), // default value is dynamic + disableSandbox: schema.maybe(schema.boolean()), // default value is dynamic in createConfig$ proxy: schema.object({ enabled: schema.boolean({ defaultValue: false }), server: schema.conditional( @@ -140,7 +135,7 @@ const CsvSchema = schema.object({ const EncryptionKeySchema = schema.conditional( schema.contextRef('dist'), true, - schema.maybe(schema.string({ minLength: 32 })), // default value is dynamic + schema.maybe(schema.string({ minLength: 32 })), // default value is dynamic in createConfig$ schema.string({ minLength: 32, defaultValue: 'a'.repeat(32) }) ); From e262dec337a01407d4c5bcde0d5e7fddbca2f86e Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 16:17:05 -0700 Subject: [PATCH 19/27] fix i18n --- x-pack/plugins/reporting/server/config/create_config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/reporting/server/config/create_config.ts b/x-pack/plugins/reporting/server/config/create_config.ts index 98dcfb637b2b8..fbb1174909555 100644 --- a/x-pack/plugins/reporting/server/config/create_config.ts +++ b/x-pack/plugins/reporting/server/config/create_config.ts @@ -78,7 +78,7 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext // disableSandbox was not set: apply default for OS const { os, disableSandbox } = await getDefaultChromiumSandboxDisabled(); logger.debug( - i18n.translate(`xpack.reporting.serverConfig.osDetected`, { + i18n.translate('xpack.reporting.serverConfig.osDetected', { defaultMessage: 'Running on OS: "{osName}", distribution: "{dist}", release: "${release}"', values: { osName: os.os, dist: os.dist, release: os.release }, From ccbcc026b40ae0d50e84d31ee894ab7a20fc4f78 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 16:34:40 -0700 Subject: [PATCH 20/27] comment --- x-pack/plugins/reporting/server/config/create_config.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/reporting/server/config/create_config.test.ts b/x-pack/plugins/reporting/server/config/create_config.test.ts index b10a73d4dd000..3107866be6496 100644 --- a/x-pack/plugins/reporting/server/config/create_config.test.ts +++ b/x-pack/plugins/reporting/server/config/create_config.test.ts @@ -54,7 +54,7 @@ describe('Reporting server createConfig$', () => { it('creates random encryption key and default config using host, protocol, and port from server info', async () => { const result = await createConfig$(mockCoreSetup, mockInitContext, mockLogger).toPromise(); - expect(result.encryptionKey).toMatch(/\S{32,}/); + expect(result.encryptionKey).toMatch(/\S{32,}/); // random 32 characters expect(result.kibanaServer).toMatchInlineSnapshot(` Object { "hostname": "kibanaHost", From 7b1f8ec54c1442f90cd78e6d2435fe36f2e587a9 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 16:50:42 -0700 Subject: [PATCH 21/27] automatically setting... logs --- x-pack/plugins/reporting/server/config/create_config.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/create_config.ts b/x-pack/plugins/reporting/server/config/create_config.ts index fbb1174909555..ba36c44e287df 100644 --- a/x-pack/plugins/reporting/server/config/create_config.ts +++ b/x-pack/plugins/reporting/server/config/create_config.ts @@ -18,7 +18,12 @@ import { ConfigSchema } from './schema'; * - xpack.kibanaServer * - xpack.reporting.encryptionKey */ -export function createConfig$(core: CoreSetup, context: PluginInitializerContext, logger: Logger) { +export function createConfig$( + core: CoreSetup, + context: PluginInitializerContext, + reportingLogger: Logger +) { + const logger = reportingLogger.get('create_config'); return context.config.create>().pipe( map(config => { // encryption key @@ -88,7 +93,7 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext if (disableSandbox) { logger.warn( i18n.translate('xpack.reporting.serverConfig.autoSet.sandboxDisabled', { - defaultMessage: `Setting '{configKey}: false' in Reporting config: not supported for {osName}`, + defaultMessage: `Automatically setting '{configKey}: false' in Reporting plugin configuration. Chromium sandbox is not supported for '{osName}.'`, values: { configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', osName: `${os.os}/${os.dist}`, From 84eccad09786f33a58205645db24b2e888f9e13e Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 17:43:53 -0700 Subject: [PATCH 22/27] replace log_configuration --- .../plugins/reporting/log_configuration.ts | 35 ------------------- .../browsers/create_browser_driver_factory.ts | 3 -- .../legacy/plugins/reporting/server/plugin.ts | 3 -- .../create_mock_reportingplugin.ts | 1 - .../reporting/server/config/create_config.ts | 29 +++++++++------ 5 files changed, 19 insertions(+), 52 deletions(-) delete mode 100644 x-pack/legacy/plugins/reporting/log_configuration.ts diff --git a/x-pack/legacy/plugins/reporting/log_configuration.ts b/x-pack/legacy/plugins/reporting/log_configuration.ts deleted file mode 100644 index 7aaed2038bd52..0000000000000 --- a/x-pack/legacy/plugins/reporting/log_configuration.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import getosSync, { LinuxOs } from 'getos'; -import { promisify } from 'util'; -import { BROWSER_TYPE } from './common/constants'; -import { CaptureConfig } from './server/types'; -import { Logger } from './types'; - -const getos = promisify(getosSync); - -export async function logConfiguration(captureConfig: CaptureConfig, logger: Logger) { - const { - browser: { - type: browserType, - chromium: { disableSandbox }, - }, - } = captureConfig; - - logger.debug(`Browser type: ${browserType}`); - if (browserType === BROWSER_TYPE) { - logger.debug(`Chromium sandbox disabled: ${disableSandbox}`); - } - - const os = await getos(); - const { os: osName, dist, release } = os as LinuxOs; - if (dist) { - logger.debug(`Running on os "${osName}", distribution "${dist}", release "${release}"`); - } else { - logger.debug(`Running on os "${osName}"`); - } -} diff --git a/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts b/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts index af3b86919dc50..401c7bd460c83 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts +++ b/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts @@ -21,9 +21,6 @@ export async function createBrowserDriverFactory( const browserType = captureConfig.browser.type; const dataDir = config.kbnConfig.get('path', 'data'); - if (browserConfig.disableSandbox) { - logger.warning(`Enabling the Chromium sandbox provides an additional layer of protection.`); - } if (browserAutoDownload) { await ensureBrowserDownloaded(browserType); } diff --git a/x-pack/legacy/plugins/reporting/server/plugin.ts b/x-pack/legacy/plugins/reporting/server/plugin.ts index 99241f8a3ab2c..e0fa99106a93e 100644 --- a/x-pack/legacy/plugins/reporting/server/plugin.ts +++ b/x-pack/legacy/plugins/reporting/server/plugin.ts @@ -5,7 +5,6 @@ */ import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/server'; -import { logConfiguration } from '../log_configuration'; import { createBrowserDriverFactory } from './browsers'; import { ReportingCore, ReportingConfig } from './core'; import { createQueueFactory, enqueueJobFactory, LevelLogger, runValidations } from './lib'; @@ -59,8 +58,6 @@ export class ReportingPlugin setFieldFormats(plugins.data.fieldFormats); - logConfiguration(this.config.get('capture'), this.logger); - return {}; } diff --git a/x-pack/legacy/plugins/reporting/test_helpers/create_mock_reportingplugin.ts b/x-pack/legacy/plugins/reporting/test_helpers/create_mock_reportingplugin.ts index 34ff91d1972a0..ec00023b4d449 100644 --- a/x-pack/legacy/plugins/reporting/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/legacy/plugins/reporting/test_helpers/create_mock_reportingplugin.ts @@ -11,7 +11,6 @@ jest.mock('../server/browsers'); jest.mock('../server/lib/create_queue'); jest.mock('../server/lib/enqueue_job'); jest.mock('../server/lib/validate'); -jest.mock('../log_configuration'); import { EventEmitter } from 'events'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths diff --git a/x-pack/plugins/reporting/server/config/create_config.ts b/x-pack/plugins/reporting/server/config/create_config.ts index ba36c44e287df..a4449bd9a5bf6 100644 --- a/x-pack/plugins/reporting/server/config/create_config.ts +++ b/x-pack/plugins/reporting/server/config/create_config.ts @@ -82,21 +82,33 @@ export function createConfig$( // disableSandbox was not set: apply default for OS const { os, disableSandbox } = await getDefaultChromiumSandboxDisabled(); + const osName = `${os.os} ${os.dist} ${os.release || ''}`; + logger.debug( i18n.translate('xpack.reporting.serverConfig.osDetected', { - defaultMessage: - 'Running on OS: "{osName}", distribution: "{dist}", release: "${release}"', - values: { osName: os.os, dist: os.dist, release: os.release }, + defaultMessage: `Running on OS: '{osName}'`, + values: { osName }, }) ); - if (disableSandbox) { + const sandboxEnabled = !disableSandbox; + if (sandboxEnabled) { + logger.info( + i18n.translate('xpack.reporting.serverConfig.autoSet.sandboxEnabled', { + defaultMessage: `Automatically setting '{configKey}: true'. Supported OS: {osName}`, + values: { + configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', + osName, + }, + }) + ); + } else { logger.warn( i18n.translate('xpack.reporting.serverConfig.autoSet.sandboxDisabled', { - defaultMessage: `Automatically setting '{configKey}: false' in Reporting plugin configuration. Chromium sandbox is not supported for '{osName}.'`, + defaultMessage: `Automatically setting '{configKey}: false'. Chromium sandbox is not supported for '{osName}.'`, values: { configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', - osName: `${os.os}/${os.dist}`, + osName, }, }) ); @@ -108,10 +120,7 @@ export function createConfig$( ...config.capture, browser: { ...config.capture.browser, - chromium: { - ...config.capture.browser.chromium, - disableSandbox, - }, + chromium: { ...config.capture.browser.chromium, disableSandbox }, }, }, }; From c7cefe942816b7d9726b4f5c78fdb52d9fcd9c3e Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 18:18:15 -0700 Subject: [PATCH 23/27] fix lint --- .../reporting/server/browsers/create_browser_driver_factory.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts b/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts index 401c7bd460c83..a934315302cbe 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts +++ b/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts @@ -16,7 +16,6 @@ export async function createBrowserDriverFactory( logger: Logger ): Promise { const captureConfig = config.get('capture'); - const browserConfig = captureConfig.browser.chromium; const browserAutoDownload = captureConfig.browser.autoDownload; const browserType = captureConfig.browser.type; const dataDir = config.kbnConfig.get('path', 'data'); From 611e2aaae943404b02f03c870f412010398ba293 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Apr 2020 18:18:42 -0700 Subject: [PATCH 24/27] This is f2 --- x-pack/plugins/reporting/server/config/create_config.ts | 9 ++------- .../server/config/default_chromium_sandbox_disabled.ts | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/create_config.ts b/x-pack/plugins/reporting/server/config/create_config.ts index a4449bd9a5bf6..f558e054cafad 100644 --- a/x-pack/plugins/reporting/server/config/create_config.ts +++ b/x-pack/plugins/reporting/server/config/create_config.ts @@ -18,12 +18,7 @@ import { ConfigSchema } from './schema'; * - xpack.kibanaServer * - xpack.reporting.encryptionKey */ -export function createConfig$( - core: CoreSetup, - context: PluginInitializerContext, - reportingLogger: Logger -) { - const logger = reportingLogger.get('create_config'); +export function createConfig$(core: CoreSetup, context: PluginInitializerContext, logger: Logger) { return context.config.create>().pipe( map(config => { // encryption key @@ -82,7 +77,7 @@ export function createConfig$( // disableSandbox was not set: apply default for OS const { os, disableSandbox } = await getDefaultChromiumSandboxDisabled(); - const osName = `${os.os} ${os.dist} ${os.release || ''}`; + const osName = [os.os, os.dist, os.release].filter(Boolean).join(' '); logger.debug( i18n.translate('xpack.reporting.serverConfig.osDetected', { diff --git a/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts index 4c24a0e7cd794..525041d5c772b 100644 --- a/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts +++ b/x-pack/plugins/reporting/server/config/default_chromium_sandbox_disabled.ts @@ -33,7 +33,7 @@ const distroSupportsUnprivilegedUsernamespaces = (distro: string) => { interface OsSummary { disableSandbox: boolean; - os: { os: string; dist: string; release: string }; + os: { os: string; dist?: string; release?: string }; } export async function getDefaultChromiumSandboxDisabled(): Promise { @@ -42,6 +42,6 @@ export async function getDefaultChromiumSandboxDisabled(): Promise { if (os.os === 'linux' && !distroSupportsUnprivilegedUsernamespaces(os.dist)) { return { os, disableSandbox: true }; } else { - return { os: { ...os, dist: 'unknown', release: 'unknown' }, disableSandbox: false }; + return { os, disableSandbox: false }; } } From e72852623d3529b43c97049d78fbcca970dfcb30 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Sat, 11 Apr 2020 08:59:28 -0700 Subject: [PATCH 25/27] improve startup log about sandbox info --- .../reporting/server/config/create_config.ts | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/create_config.ts b/x-pack/plugins/reporting/server/config/create_config.ts index f558e054cafad..1e6e8bbde5d27 100644 --- a/x-pack/plugins/reporting/server/config/create_config.ts +++ b/x-pack/plugins/reporting/server/config/create_config.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n/'; import { TypeOf } from '@kbn/config-schema'; import crypto from 'crypto'; +import { capitalize } from 'lodash'; import { map, mergeMap } from 'rxjs/operators'; import { CoreSetup, Logger, PluginInitializerContext } from 'src/core/server'; import { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; @@ -75,9 +76,12 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext return config; } - // disableSandbox was not set: apply default for OS + // disableSandbox was not set by user, apply default for OS const { os, disableSandbox } = await getDefaultChromiumSandboxDisabled(); - const osName = [os.os, os.dist, os.release].filter(Boolean).join(' '); + const osName = [os.os, os.dist, os.release] + .filter(Boolean) + .map(capitalize) + .join(' '); logger.debug( i18n.translate('xpack.reporting.serverConfig.osDetected', { @@ -86,11 +90,10 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext }) ); - const sandboxEnabled = !disableSandbox; - if (sandboxEnabled) { - logger.info( - i18n.translate('xpack.reporting.serverConfig.autoSet.sandboxEnabled', { - defaultMessage: `Automatically setting '{configKey}: true'. Supported OS: {osName}`, + if (disableSandbox === true) { + logger.warn( + i18n.translate('xpack.reporting.serverConfig.autoSet.sandboxDisabled', { + defaultMessage: `Chromium sandbox provides an additional layer of protection, but is not supported for {osName} OS. Automatically setting '{configKey}: true'.`, values: { configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', osName, @@ -98,13 +101,10 @@ export function createConfig$(core: CoreSetup, context: PluginInitializerContext }) ); } else { - logger.warn( - i18n.translate('xpack.reporting.serverConfig.autoSet.sandboxDisabled', { - defaultMessage: `Automatically setting '{configKey}: false'. Chromium sandbox is not supported for '{osName}.'`, - values: { - configKey: 'xpack.reporting.capture.browser.chromium.disableSandbox', - osName, - }, + logger.info( + i18n.translate('xpack.reporting.serverConfig.autoSet.sandboxEnabled', { + defaultMessage: `Chromium sandbox provides an additional layer of protection, and is supported for {osName} OS. Automatically enabling Chromium sandbox.`, + values: { osName }, }) ); } From a0e045b2b9664db2399abe96f775376c6c7df10a Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Sat, 11 Apr 2020 09:08:06 -0700 Subject: [PATCH 26/27] update docs with log reference --- docs/user/reporting/chromium-sandbox.asciidoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/user/reporting/chromium-sandbox.asciidoc b/docs/user/reporting/chromium-sandbox.asciidoc index 5d4fbfb153a0b..bfef5b8b86c6b 100644 --- a/docs/user/reporting/chromium-sandbox.asciidoc +++ b/docs/user/reporting/chromium-sandbox.asciidoc @@ -11,12 +11,12 @@ sandboxing techniques differ for each operating system. The Linux sandbox depends on user namespaces, which were introduced with the 3.8 Linux kernel. However, many distributions don't have user namespaces enabled by default, or they require the CAP_SYS_ADMIN capability. {reporting} will automatically disable the sandbox when it is running on Debian and CentOS as additional steps are required to enable -unprivileged usernamespaces. In these situations, you'll see the following message in your {kib} logs: -`Enabling the Chromium sandbox provides an additional layer of protection`. +unprivileged usernamespaces. In these situations, you'll see the following message in your {kib} startup logs: +`Chromium sandbox provides an additional layer of protection, but is not supported for your OS. +Automatically setting 'xpack.reporting.capture.browser.chromium.disableSandbox: true'.` -If your kernel is 3.8 or newer, it's -recommended to enable usernamespaces and set `xpack.reporting.capture.browser.chromium.disableSandbox: false` in your -`kibana.yml` to enable the sandbox. +Reporting will automatically enable the Chromium sandbox at startup when a supported OS is detected. However, if your kernel is 3.8 or newer, it's +recommended to set `xpack.reporting.capture.browser.chromium.disableSandbox: false` in your `kibana.yml` to explicitly enable usernamespaces. ==== Docker When running {kib} in a Docker container, all container processes are run within a usernamespace with seccomp-bpf and From 8c19295b4212758ac6a8dd5dadcd9032d8005913 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Sat, 11 Apr 2020 20:45:47 -0700 Subject: [PATCH 27/27] revert log removal --- .../server/browsers/create_browser_driver_factory.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts b/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts index a934315302cbe..af3b86919dc50 100644 --- a/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts +++ b/x-pack/legacy/plugins/reporting/server/browsers/create_browser_driver_factory.ts @@ -16,10 +16,14 @@ export async function createBrowserDriverFactory( logger: Logger ): Promise { const captureConfig = config.get('capture'); + const browserConfig = captureConfig.browser.chromium; const browserAutoDownload = captureConfig.browser.autoDownload; const browserType = captureConfig.browser.type; const dataDir = config.kbnConfig.get('path', 'data'); + if (browserConfig.disableSandbox) { + logger.warning(`Enabling the Chromium sandbox provides an additional layer of protection.`); + } if (browserAutoDownload) { await ensureBrowserDownloaded(browserType); }