[Reporting] Validate export types with config before registering in reporting (#162815)

## Summary

Export types shouldn't be registered in the reporting plugins' export
type registry if they are not enabled in the config. This PR will
restrict any users who may try API calls in the serverless offering
where image reporting should not be supported.

This PR continues the work of
https://github.com/elastic/kibana/pull/162358

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Tim Sullivan <tsullivan@users.noreply.github.com>
This commit is contained in:
Rachel Shen 2023-08-07 07:04:33 -06:00 committed by GitHub
parent ce5024da9f
commit 974979bdf7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 15 deletions

View file

@ -66,6 +66,17 @@ describe('Reporting server createConfig', () => {
},
},
"encryptionKey": "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii",
"export_types": Object {
"csv": Object {
"enabled": true,
},
"pdf": Object {
"enabled": true,
},
"png": Object {
"enabled": true,
},
},
"index": ".reporting",
"kibanaServer": Object {
"hostname": "reportingHost",

View file

@ -109,7 +109,6 @@ export class ReportingCore {
private monitorTask: MonitorReportsTask;
private config: ReportingConfigType;
private executing: Set<string>;
private exportTypes: ExportType[] = [];
private exportTypesRegistry = new ExportTypesRegistry();
public getContract: () => ReportingSetup;
@ -125,20 +124,9 @@ export class ReportingCore {
const config = createConfig(core, context.config.get<ReportingConfigType>(), logger);
this.config = config;
// Export Type declarations
this.exportTypes.push(
new CsvSearchSourceExportType(this.core, this.config, this.logger, this.context)
);
this.exportTypes.push(new CsvV2ExportType(this.core, this.config, this.logger, this.context));
this.exportTypes.push(new PdfExportType(this.core, this.config, this.logger, this.context));
this.exportTypes.push(new PngExportType(this.core, this.config, this.logger, this.context));
// deprecated export types for tests
this.exportTypes.push(new PdfV1ExportType(this.core, this.config, this.logger, this.context));
this.exportTypes.forEach((et) => {
this.getExportTypes().forEach((et) => {
this.exportTypesRegistry.register(et);
});
this.deprecatedAllowedRoles = config.roles.enabled ? config.roles.allow : false;
this.executeTask = new ExecuteReportTask(this, config, this.logger);
this.monitorTask = new MonitorReportsTask(this, config, this.logger);
@ -164,7 +152,7 @@ export class ReportingCore {
this.pluginSetup$.next(true); // trigger the observer
this.pluginSetupDeps = setupDeps; // cache
this.exportTypes.forEach((et) => {
this.exportTypesRegistry.getAll().forEach((et) => {
et.setup(setupDeps);
});
@ -182,7 +170,7 @@ export class ReportingCore {
this.pluginStart$.next(startDeps); // trigger the observer
this.pluginStartDeps = startDeps; // cache
this.exportTypes.forEach((et) => {
this.exportTypesRegistry.getAll().forEach((et) => {
et.start({ ...startDeps, reporting: this.getContract() });
});
@ -233,6 +221,30 @@ export class ReportingCore {
this.pluginSetup$.next(true);
}
/**
* Validate export types with config settings
* only CSV export types should be registered in the export types registry for serverless
*/
private getExportTypes(): ExportType[] {
const exportTypes = [];
if (!this.config.export_types.pdf.enabled || !this.config.export_types.png.enabled) {
exportTypes.push(
new CsvSearchSourceExportType(this.core, this.config, this.logger, this.context)
);
exportTypes.push(new CsvV2ExportType(this.core, this.config, this.logger, this.context));
} else {
exportTypes.push(
new CsvSearchSourceExportType(this.core, this.config, this.logger, this.context)
);
exportTypes.push(new CsvV2ExportType(this.core, this.config, this.logger, this.context));
exportTypes.push(new PdfExportType(this.core, this.config, this.logger, this.context));
exportTypes.push(new PngExportType(this.core, this.config, this.logger, this.context));
// deprecated export types for tests
exportTypes.push(new PdfV1ExportType(this.core, this.config, this.logger, this.context));
}
return exportTypes;
}
/**
* If xpack.reporting.roles.enabled === true, register Reporting as a feature
* that is controlled by user role names

View file

@ -7,6 +7,7 @@
import type { CoreSetup, CoreStart, Logger } from '@kbn/core/server';
import { coreMock, loggingSystemMock } from '@kbn/core/server/mocks';
import { PDF_REPORT_TYPE_V2, PNG_REPORT_TYPE_V2 } from '../common/constants/report_types';
import type { ReportingCore, ReportingInternalStart } from './core';
import { ReportingPlugin } from './plugin';
import {
@ -80,4 +81,50 @@ describe('Reporting Plugin', () => {
`);
expect(logger.error).toHaveBeenCalledTimes(2);
});
describe('config and export types registry validation', () => {
it('expect image reporting to be in registry by default', async () => {
// wait for the setup phase background work
plugin.setup(coreSetup, pluginSetup);
await new Promise(setImmediate);
// create a way for an error to happen
const reportingCore = (plugin as unknown as { reportingCore: ReportingCore }).reportingCore;
// wait for the startup phase background work
plugin.start(coreStart, pluginStart);
await new Promise(setImmediate);
expect(reportingCore.getExportTypesRegistry().getById(PDF_REPORT_TYPE_V2)).toHaveProperty(
'id',
PDF_REPORT_TYPE_V2
);
expect(reportingCore.getExportTypesRegistry().getById(PNG_REPORT_TYPE_V2)).toHaveProperty(
'id',
PNG_REPORT_TYPE_V2
);
});
it('expect pdf to not be in registry if config does not enable it', async () => {
configSchema = { ...createMockConfigSchema(), export_types: { pdf: { enabled: false } } };
initContext = coreMock.createPluginInitializerContext(configSchema);
coreSetup = coreMock.createSetup(configSchema);
coreStart = coreMock.createStart();
pluginSetup = createMockPluginSetup({}) as unknown as ReportingSetupDeps;
pluginStart = await createMockPluginStart(coreStart, configSchema);
plugin = new ReportingPlugin(initContext);
// wait for the setup phase background work
plugin.setup(coreSetup, pluginSetup);
await new Promise(setImmediate);
// create a way for an error to happen
const reportingCore = (plugin as unknown as { reportingCore: ReportingCore }).reportingCore;
// wait for the startup phase background work
plugin.start(coreStart, pluginStart);
await new Promise(setImmediate);
const checkPdf = () => reportingCore.getExportTypesRegistry().getById(PDF_REPORT_TYPE_V2);
const checkPng = () => reportingCore.getExportTypesRegistry().getById(PNG_REPORT_TYPE_V2);
expect(checkPdf).toThrowError(`Unknown id ${PDF_REPORT_TYPE_V2}`);
expect(checkPng).toThrowError(`Unknown id ${PNG_REPORT_TYPE_V2}`);
});
});
});

View file

@ -111,6 +111,11 @@ export const createMockConfigSchema = (
...overrides.roles,
},
capture: { maxAttempts: 1 },
export_types: {
pdf: { enabled: true },
png: { enabled: true },
csv: { enabled: true },
},
} as ReportingConfigType;
};