Skip to content

Commit

Permalink
[Reporting] Use a shim for server config (#62086)
Browse files Browse the repository at this point in the history
* config shim

* simplify route register calls

* switch to in-sync worker functions

* fix tests

* comment

* fix set up config with defaults

* reduce loc change

* remove test for removed file

* reportingconfigtype

* revert changing executeJobFactory to synchronous

* imports cleanup

* Clean up some awaits

* undo comment

* clean up async

* clean up imports

* add warning logs for config defaults

* Move around some config shim code

* Register routes params take ReportingCore

* usageCollection is an optional dependency
  • Loading branch information
tsullivan authored Apr 4, 2020
1 parent a5c3865 commit f1f93d3
Show file tree
Hide file tree
Showing 90 changed files with 1,101 additions and 1,525 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,27 @@
*/

import { cryptoFactory } from '../../../server/lib/crypto';
import { createMockServer } from '../../../test_helpers';
import { Logger } from '../../../types';
import { decryptJobHeaders } from './decrypt_job_headers';

let mockServer: any;
beforeEach(() => {
mockServer = createMockServer('');
});

const encryptHeaders = async (headers: Record<string, string>) => {
const crypto = cryptoFactory(mockServer);
const encryptHeaders = async (encryptionKey: string, headers: Record<string, string>) => {
const crypto = cryptoFactory(encryptionKey);
return await crypto.encrypt(headers);
};

describe('headers', () => {
test(`fails if it can't decrypt headers`, async () => {
await expect(
const getDecryptedHeaders = () =>
decryptJobHeaders({
encryptionKey: 'abcsecretsauce',
job: {
headers: 'Q53+9A+zf+Xe+ceR/uB/aR/Sw/8e+M+qR+WiG+8z+EY+mo+HiU/zQL+Xn',
},
logger: ({
error: jest.fn(),
} as unknown) as Logger,
server: mockServer,
})
).rejects.toMatchInlineSnapshot(
});
await expect(getDecryptedHeaders()).rejects.toMatchInlineSnapshot(
`[Error: Failed to decrypt report job data. Please ensure that xpack.reporting.encryptionKey is set and re-generate this report. Error: Invalid IV length]`
);
});
Expand All @@ -42,15 +36,15 @@ describe('headers', () => {
baz: 'quix',
};

const encryptedHeaders = await encryptHeaders(headers);
const encryptedHeaders = await encryptHeaders('abcsecretsauce', headers);
const decryptedHeaders = await decryptJobHeaders({
encryptionKey: 'abcsecretsauce',
job: {
title: 'cool-job-bro',
type: 'csv',
headers: encryptedHeaders,
},
logger: {} as Logger,
server: mockServer,
});
expect(decryptedHeaders).toEqual(headers);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { i18n } from '@kbn/i18n';
import { cryptoFactory } from '../../../server/lib/crypto';
import { CryptoFactory, ServerFacade, Logger } from '../../../types';
import { CryptoFactory, Logger } from '../../../types';

interface HasEncryptedHeaders {
headers?: string;
Expand All @@ -17,15 +17,15 @@ export const decryptJobHeaders = async <
JobParamsType,
JobDocPayloadType extends HasEncryptedHeaders
>({
server,
encryptionKey,
job,
logger,
}: {
server: ServerFacade;
encryptionKey?: string;
job: JobDocPayloadType;
logger: Logger;
}): Promise<Record<string, string>> => {
const crypto: CryptoFactory = cryptoFactory(server);
const crypto: CryptoFactory = cryptoFactory(encryptionKey);
try {
const decryptedHeaders: Record<string, string> = await crypto.decrypt(job.headers);
return decryptedHeaders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,32 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createMockReportingCore, createMockServer } from '../../../test_helpers';
import { ReportingCore } from '../../../server';
import sinon from 'sinon';
import { createMockReportingCore } from '../../../test_helpers';
import { ReportingConfig, ReportingCore } from '../../../server/types';
import { JobDocPayload } from '../../../types';
import { JobDocPayloadPDF } from '../../printable_pdf/types';
import { getConditionalHeaders, getCustomLogo } from './index';

let mockConfig: ReportingConfig;
let mockReportingPlugin: ReportingCore;
let mockServer: any;

const getMockConfig = (mockConfigGet: sinon.SinonStub) => ({
get: mockConfigGet,
kbnConfig: { get: mockConfigGet },
});

beforeEach(async () => {
mockReportingPlugin = await createMockReportingCore();
mockServer = createMockServer('');
const mockConfigGet = sinon
.stub()
.withArgs('kibanaServer', 'hostname')
.returns('custom-hostname');
mockConfig = getMockConfig(mockConfigGet);
mockReportingPlugin = await createMockReportingCore(mockConfig);
});

describe('conditions', () => {
test(`uses hostname from reporting config if set`, async () => {
const settings: any = {
'xpack.reporting.kibanaServer.hostname': 'custom-hostname',
};

mockServer = createMockServer({ settings });

const permittedHeaders = {
foo: 'bar',
baz: 'quix',
Expand All @@ -33,121 +38,20 @@ describe('conditions', () => {
const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
config: mockConfig,
});

expect(conditionalHeaders.conditions.hostname).toEqual(
mockServer.config().get('xpack.reporting.kibanaServer.hostname')
mockConfig.get('kibanaServer', 'hostname')
);
});

test(`uses hostname from server.config if reporting config not set`, async () => {
const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.hostname).toEqual(mockServer.config().get('server.host'));
});

test(`uses port from reporting config if set`, async () => {
const settings = {
'xpack.reporting.kibanaServer.port': 443,
};

mockServer = createMockServer({ settings });

const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.port).toEqual(
mockServer.config().get('xpack.reporting.kibanaServer.port')
expect(conditionalHeaders.conditions.port).toEqual(mockConfig.get('kibanaServer', 'port'));
expect(conditionalHeaders.conditions.protocol).toEqual(
mockConfig.get('kibanaServer', 'protocol')
);
});

test(`uses port from server if reporting config not set`, async () => {
const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.port).toEqual(mockServer.config().get('server.port'));
});

test(`uses basePath from server config`, async () => {
const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.basePath).toEqual(
mockServer.config().get('server.basePath')
mockConfig.kbnConfig.get('server', 'basePath')
);
});

test(`uses protocol from reporting config if set`, async () => {
const settings = {
'xpack.reporting.kibanaServer.protocol': 'https',
};

mockServer = createMockServer({ settings });

const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.protocol).toEqual(
mockServer.config().get('xpack.reporting.kibanaServer.protocol')
);
});

test(`uses protocol from server.info`, async () => {
const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.protocol).toEqual(mockServer.info.protocol);
});
});

test('uses basePath from job when creating saved object service', async () => {
Expand All @@ -161,14 +65,14 @@ test('uses basePath from job when creating saved object service', async () => {
const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
config: mockConfig,
});
const jobBasePath = '/sbp/s/marketing';
await getCustomLogo({
reporting: mockReportingPlugin,
job: { basePath: jobBasePath } as JobDocPayloadPDF,
conditionalHeaders,
server: mockServer,
config: mockConfig,
});

const getBasePath = mockGetSavedObjectsClient.mock.calls[0][0].getBasePath;
Expand All @@ -179,21 +83,26 @@ test(`uses basePath from server if job doesn't have a basePath when creating sav
const mockGetSavedObjectsClient = jest.fn();
mockReportingPlugin.getSavedObjectsClient = mockGetSavedObjectsClient;

const mockConfigGet = sinon.stub();
mockConfigGet.withArgs('kibanaServer', 'hostname').returns('localhost');
mockConfigGet.withArgs('server', 'basePath').returns('/sbp');
mockConfig = getMockConfig(mockConfigGet);

const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};
const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
config: mockConfig,
});

await getCustomLogo({
reporting: mockReportingPlugin,
job: {} as JobDocPayloadPDF,
conditionalHeaders,
server: mockServer,
config: mockConfig,
});

const getBasePath = mockGetSavedObjectsClient.mock.calls[0][0].getBasePath;
Expand Down Expand Up @@ -225,19 +134,26 @@ test(`uses basePath from server if job doesn't have a basePath when creating sav

describe('config formatting', () => {
test(`lowercases server.host`, async () => {
mockServer = createMockServer({ settings: { 'server.host': 'COOL-HOSTNAME' } });
const mockConfigGet = sinon
.stub()
.withArgs('server', 'host')
.returns('COOL-HOSTNAME');
mockConfig = getMockConfig(mockConfigGet);

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: {},
server: mockServer,
config: mockConfig,
});
expect(conditionalHeaders.conditions.hostname).toEqual('cool-hostname');
});

test(`lowercases xpack.reporting.kibanaServer.hostname`, async () => {
mockServer = createMockServer({
settings: { 'xpack.reporting.kibanaServer.hostname': 'GREAT-HOSTNAME' },
});
test(`lowercases kibanaServer.hostname`, async () => {
const mockConfigGet = sinon
.stub()
.withArgs('kibanaServer', 'hostname')
.returns('GREAT-HOSTNAME');
mockConfig = getMockConfig(mockConfigGet);
const conditionalHeaders = await getConditionalHeaders({
job: {
title: 'cool-job-bro',
Expand All @@ -249,7 +165,7 @@ describe('config formatting', () => {
},
},
filteredHeaders: {},
server: mockServer,
config: mockConfig,
});
expect(conditionalHeaders.conditions.hostname).toEqual('great-hostname');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,31 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { ConditionalHeaders, ServerFacade } from '../../../types';

import { ReportingConfig } from '../../../server/types';
import { ConditionalHeaders } from '../../../types';

export const getConditionalHeaders = <JobDocPayloadType>({
server,
config,
job,
filteredHeaders,
}: {
server: ServerFacade;
config: ReportingConfig;
job: JobDocPayloadType;
filteredHeaders: Record<string, string>;
}) => {
const config = server.config();
const { kbnConfig } = config;
const [hostname, port, basePath, protocol] = [
config.get('xpack.reporting.kibanaServer.hostname') || config.get('server.host'),
config.get('xpack.reporting.kibanaServer.port') || config.get('server.port'),
config.get('server.basePath'),
config.get('xpack.reporting.kibanaServer.protocol') || server.info.protocol,
config.get('kibanaServer', 'hostname'),
config.get('kibanaServer', 'port'),
kbnConfig.get('server', 'basePath'),
config.get('kibanaServer', 'protocol'),
] as [string, number, string, string];

const conditionalHeaders: ConditionalHeaders = {
headers: filteredHeaders,
conditions: {
hostname: hostname.toLowerCase(),
hostname: hostname ? hostname.toLowerCase() : hostname,
port,
basePath,
protocol,
Expand Down
Loading

0 comments on commit f1f93d3

Please sign in to comment.