[Reporting] Use the deprecations service to advise critical config changes (#100427)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
f3c846cc4f
commit
417c06b9a1
|
@ -45,7 +45,7 @@ describe('deprecations', () => {
|
|||
const { messages } = applyReportingDeprecations({ roles: { enabled: true } });
|
||||
expect(messages).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"\\"xpack.reporting.roles\\" is deprecated. Granting reporting privilege through a \\"reporting_user\\" role will not be supported starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privilege to users through feature controls in Management > Security > Roles",
|
||||
"\\"xpack.reporting.roles\\" is deprecated. Granting reporting privilege through a \\"reporting_user\\" role will not be supported starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privileges to users using Kibana application privileges **Management > Security > Roles**.",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -35,8 +35,8 @@ export const config: PluginConfigDescriptor<ReportingConfigType> = {
|
|||
addDeprecation({
|
||||
message:
|
||||
`"${fromPath}.roles" is deprecated. Granting reporting privilege through a "reporting_user" role will not be supported ` +
|
||||
`starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privilege to users ` +
|
||||
`through feature controls in Management > Security > Roles`,
|
||||
`starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privileges to users ` +
|
||||
`using Kibana application privileges **Management > Security > Roles**.`,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
@ -25,14 +25,14 @@ import { SecurityPluginSetup } from '../../security/server';
|
|||
import { DEFAULT_SPACE_ID } from '../../spaces/common/constants';
|
||||
import { SpacesPluginSetup } from '../../spaces/server';
|
||||
import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server';
|
||||
import { ReportingConfig } from './';
|
||||
import { ReportingConfig, ReportingSetup } from './';
|
||||
import { HeadlessChromiumDriverFactory } from './browsers/chromium/driver_factory';
|
||||
import { ReportingConfigType } from './config';
|
||||
import { checkLicense, getExportTypesRegistry, LevelLogger } from './lib';
|
||||
import { screenshotsObservableFactory, ScreenshotsObservableFn } from './lib/screenshots';
|
||||
import { ReportingStore } from './lib/store';
|
||||
import { ExecuteReportTask, MonitorReportsTask, ReportTaskParams } from './lib/tasks';
|
||||
import { ReportingPluginRouter, ReportingStart } from './types';
|
||||
import { ReportingPluginRouter } from './types';
|
||||
|
||||
export interface ReportingInternalSetup {
|
||||
basePath: Pick<BasePath, 'set'>;
|
||||
|
@ -69,7 +69,7 @@ export class ReportingCore {
|
|||
private config?: ReportingConfig; // final config, includes dynamic values based on OS type
|
||||
private executing: Set<string>;
|
||||
|
||||
public getStartContract: () => ReportingStart;
|
||||
public getContract: () => ReportingSetup;
|
||||
|
||||
constructor(private logger: LevelLogger, context: PluginInitializerContext<ReportingConfigType>) {
|
||||
const syncConfig = context.config.get<ReportingConfigType>();
|
||||
|
@ -77,11 +77,9 @@ export class ReportingCore {
|
|||
this.executeTask = new ExecuteReportTask(this, syncConfig, this.logger);
|
||||
this.monitorTask = new MonitorReportsTask(this, syncConfig, this.logger);
|
||||
|
||||
this.getStartContract = (): ReportingStart => {
|
||||
return {
|
||||
usesUiCapabilities: () => syncConfig.roles.enabled === false,
|
||||
};
|
||||
};
|
||||
this.getContract = () => ({
|
||||
usesUiCapabilities: () => syncConfig.roles.enabled === false,
|
||||
});
|
||||
|
||||
this.executing = new Set();
|
||||
}
|
||||
|
|
107
x-pack/plugins/reporting/server/deprecations.test.ts
Normal file
107
x-pack/plugins/reporting/server/deprecations.test.ts
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ReportingCore } from '.';
|
||||
import { registerDeprecations } from './deprecations';
|
||||
import { createMockConfigSchema, createMockReportingCore } from './test_helpers';
|
||||
import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks';
|
||||
import { GetDeprecationsContext, IScopedClusterClient } from 'kibana/server';
|
||||
|
||||
let reportingCore: ReportingCore;
|
||||
let context: GetDeprecationsContext;
|
||||
let esClient: jest.Mocked<IScopedClusterClient>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const mockReportingConfig = createMockConfigSchema({ roles: { enabled: false } });
|
||||
reportingCore = await createMockReportingCore(mockReportingConfig);
|
||||
esClient = elasticsearchServiceMock.createScopedClusterClient();
|
||||
esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({
|
||||
body: { xyz: { username: 'normal_user', roles: ['data_analyst'] } },
|
||||
});
|
||||
context = ({ esClient } as unknown) as GetDeprecationsContext;
|
||||
});
|
||||
|
||||
test('logs no deprecations when setup has no issues', async () => {
|
||||
const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup());
|
||||
expect(await getDeprecations(context)).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('logs a plain message when only a reporting_user role issue is found', async () => {
|
||||
esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({
|
||||
body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } },
|
||||
});
|
||||
|
||||
const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup());
|
||||
expect(await getDeprecations(context)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"correctiveActions": Object {
|
||||
"manualSteps": Array [
|
||||
"Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.",
|
||||
"Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).",
|
||||
],
|
||||
},
|
||||
"documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html",
|
||||
"level": "critical",
|
||||
"message": "The deprecated \\"reporting_user\\" role has been found for 1 user(s): \\"reportron\\"",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('logs multiple entries when multiple reporting_user role issues are found', async () => {
|
||||
esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({
|
||||
body: {
|
||||
reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] },
|
||||
supercooluser: { username: 'supercooluser', roles: ['kibana_admin', 'reporting_user'] },
|
||||
},
|
||||
});
|
||||
|
||||
const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup());
|
||||
expect(await getDeprecations(context)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"correctiveActions": Object {
|
||||
"manualSteps": Array [
|
||||
"Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.",
|
||||
"Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).",
|
||||
],
|
||||
},
|
||||
"documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html",
|
||||
"level": "critical",
|
||||
"message": "The deprecated \\"reporting_user\\" role has been found for 2 user(s): \\"reportron\\", \\"supercooluser\\"",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('logs an expanded message when a config issue and a reporting_user role issue is found', async () => {
|
||||
esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({
|
||||
body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } },
|
||||
});
|
||||
|
||||
const mockReportingConfig = createMockConfigSchema({ roles: { enabled: true } });
|
||||
reportingCore = await createMockReportingCore(mockReportingConfig);
|
||||
|
||||
const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup());
|
||||
expect(await getDeprecations(context)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"correctiveActions": Object {
|
||||
"manualSteps": Array [
|
||||
"Set \\"xpack.reporting.roles.enabled: false\\" in kibana.yml",
|
||||
"Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.",
|
||||
"Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).",
|
||||
],
|
||||
},
|
||||
"documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html",
|
||||
"level": "critical",
|
||||
"message": "The deprecated \\"reporting_user\\" role has been found for 1 user(s): \\"reportron\\"",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
52
x-pack/plugins/reporting/server/deprecations.ts
Normal file
52
x-pack/plugins/reporting/server/deprecations.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { CoreSetup, DeprecationsDetails, RegisterDeprecationsConfig } from 'src/core/server';
|
||||
import { ReportingCore } from '.';
|
||||
|
||||
const deprecatedRole = 'reporting_user';
|
||||
const upgradableConfig = 'xpack.reporting.roles.enabled: false';
|
||||
|
||||
export async function registerDeprecations(
|
||||
reporting: ReportingCore,
|
||||
{ deprecations: deprecationsService }: CoreSetup
|
||||
) {
|
||||
const deprecationsConfig: RegisterDeprecationsConfig = {
|
||||
getDeprecations: async ({ esClient }) => {
|
||||
const usingDeprecatedConfig = !reporting.getContract().usesUiCapabilities();
|
||||
const deprecations: DeprecationsDetails[] = [];
|
||||
const { body: users } = await esClient.asCurrentUser.security.getUser();
|
||||
|
||||
const reportingUsers = Object.entries(users)
|
||||
.filter(([username, user]) => user.roles.includes(deprecatedRole))
|
||||
.map(([, user]) => user.username);
|
||||
const numReportingUsers = reportingUsers.length;
|
||||
|
||||
if (numReportingUsers > 0) {
|
||||
const usernames = reportingUsers.join('", "');
|
||||
deprecations.push({
|
||||
message: `The deprecated "${deprecatedRole}" role has been found for ${numReportingUsers} user(s): "${usernames}"`,
|
||||
documentationUrl: 'https://www.elastic.co/guide/en/kibana/current/secure-reporting.html',
|
||||
level: 'critical',
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
...(usingDeprecatedConfig ? [`Set "${upgradableConfig}" in kibana.yml`] : []),
|
||||
`Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.`,
|
||||
`Assign the custom role(s) as desired, and remove the "${deprecatedRole}" role from the user(s).`,
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return deprecations;
|
||||
},
|
||||
};
|
||||
|
||||
deprecationsService.registerDeprecations(deprecationsConfig);
|
||||
|
||||
return deprecationsConfig;
|
||||
}
|
|
@ -10,6 +10,7 @@ import { PLUGIN_ID } from '../common/constants';
|
|||
import { ReportingCore } from './';
|
||||
import { initializeBrowserDriverFactory } from './browsers';
|
||||
import { buildConfig, registerUiSettings, ReportingConfigType } from './config';
|
||||
import { registerDeprecations } from './deprecations';
|
||||
import { LevelLogger, ReportingStore } from './lib';
|
||||
import { registerRoutes } from './routes';
|
||||
import { setFieldFormats } from './services';
|
||||
|
@ -38,15 +39,13 @@ export class ReportingPlugin
|
|||
// @ts-expect-error null is not assignable to object. use a boolean property to ensure reporting API is enabled.
|
||||
core.http.registerRouteHandlerContext(PLUGIN_ID, () => {
|
||||
if (reportingCore.pluginIsStarted()) {
|
||||
return reportingCore.getStartContract();
|
||||
return reportingCore.getContract();
|
||||
} else {
|
||||
this.logger.error(`Reporting features are not yet ready`);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
registerUiSettings(core);
|
||||
|
||||
const { http } = core;
|
||||
const { screenshotMode, features, licensing, security, spaces, taskManager } = plugins;
|
||||
|
||||
|
@ -65,6 +64,8 @@ export class ReportingPlugin
|
|||
logger: this.logger,
|
||||
});
|
||||
|
||||
registerUiSettings(core);
|
||||
registerDeprecations(reportingCore, core);
|
||||
registerReportingUsageCollector(reportingCore, plugins);
|
||||
registerRoutes(reportingCore, this.logger);
|
||||
|
||||
|
@ -81,7 +82,7 @@ export class ReportingPlugin
|
|||
});
|
||||
|
||||
this.reportingCore = reportingCore;
|
||||
return reportingCore.getStartContract();
|
||||
return reportingCore.getContract();
|
||||
}
|
||||
|
||||
public start(core: CoreStart, plugins: ReportingStartDeps) {
|
||||
|
@ -116,6 +117,6 @@ export class ReportingPlugin
|
|||
this.logger.error(e);
|
||||
});
|
||||
|
||||
return reportingCore.getStartContract();
|
||||
return reportingCore.getContract();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue