[Alerting] Fixing broken Alerts view when no Global All Kibana privilege (#88727)
* Making kibanaFeatures an optional parameter and catching error on plugin start * Gracefully handle 404 errors when no access to features endpoint * Adding functional test
This commit is contained in:
parent
e3063f6934
commit
6d1c010607
|
@ -9,6 +9,7 @@ import { CoreSetup, CoreStart, Plugin as CorePlugin } from 'src/core/public';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
import { FeaturesPluginStart } from '../../features/public';
|
import { FeaturesPluginStart } from '../../features/public';
|
||||||
|
import { KibanaFeature } from '../../features/common';
|
||||||
import { registerBuiltInActionTypes } from './application/components/builtin_action_types';
|
import { registerBuiltInActionTypes } from './application/components/builtin_action_types';
|
||||||
import { ActionTypeModel, AlertTypeModel } from './types';
|
import { ActionTypeModel, AlertTypeModel } from './types';
|
||||||
import { TypeRegistry } from './application/type_registry';
|
import { TypeRegistry } from './application/type_registry';
|
||||||
|
@ -122,7 +123,17 @@ export class Plugin
|
||||||
];
|
];
|
||||||
|
|
||||||
const { renderApp } = await import('./application/app');
|
const { renderApp } = await import('./application/app');
|
||||||
const kibanaFeatures = await pluginsStart.features.getFeatures();
|
|
||||||
|
// The `/api/features` endpoint requires the "Global All" Kibana privilege. Users with a
|
||||||
|
// subset of this privilege are not authorized to access this endpoint and will receive a 404
|
||||||
|
// error that causes the Alerting view to fail to load.
|
||||||
|
let kibanaFeatures: KibanaFeature[];
|
||||||
|
try {
|
||||||
|
kibanaFeatures = await pluginsStart.features.getFeatures();
|
||||||
|
} catch (err) {
|
||||||
|
kibanaFeatures = [];
|
||||||
|
}
|
||||||
|
|
||||||
return renderApp({
|
return renderApp({
|
||||||
...coreStart,
|
...coreStart,
|
||||||
data: pluginsStart.data,
|
data: pluginsStart.data,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { getTestAlertData, getTestActionData } from '../../lib/get_test_data';
|
||||||
|
|
||||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
const testSubjects = getService('testSubjects');
|
const testSubjects = getService('testSubjects');
|
||||||
|
const security = getService('security');
|
||||||
const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']);
|
const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']);
|
||||||
const log = getService('log');
|
const log = getService('log');
|
||||||
const browser = getService('browser');
|
const browser = getService('browser');
|
||||||
|
@ -18,80 +19,97 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
const objectRemover = new ObjectRemover(supertest);
|
const objectRemover = new ObjectRemover(supertest);
|
||||||
|
|
||||||
describe('Home page', function () {
|
describe('Home page', function () {
|
||||||
before(async () => {
|
describe('Loads the app with limited privileges', () => {
|
||||||
await pageObjects.common.navigateToApp('triggersActions');
|
before(async () => {
|
||||||
});
|
await security.testUser.setRoles(['alerts_and_actions_role'], true);
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await security.testUser.restoreDefaults();
|
||||||
|
});
|
||||||
|
|
||||||
after(async () => {
|
it('Loads the Alerts page', async () => {
|
||||||
await objectRemover.removeAll();
|
await pageObjects.common.navigateToApp('triggersActions');
|
||||||
});
|
const headingText = await pageObjects.triggersActionsUI.getSectionHeadingText();
|
||||||
|
expect(headingText).to.be('Alerts and Actions');
|
||||||
it('Loads the app', async () => {
|
|
||||||
await log.debug('Checking for section heading to say Triggers and Actions.');
|
|
||||||
|
|
||||||
const headingText = await pageObjects.triggersActionsUI.getSectionHeadingText();
|
|
||||||
expect(headingText).to.be('Alerts and Actions');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Connectors tab', () => {
|
|
||||||
it('renders the connectors tab', async () => {
|
|
||||||
// Navigate to the connectors tab
|
|
||||||
await pageObjects.triggersActionsUI.changeTabs('connectorsTab');
|
|
||||||
|
|
||||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
|
||||||
|
|
||||||
// Verify url
|
|
||||||
const url = await browser.getCurrentUrl();
|
|
||||||
expect(url).to.contain(`/connectors`);
|
|
||||||
|
|
||||||
// Verify content
|
|
||||||
await testSubjects.existOrFail('actionsList');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Alerts tab', () => {
|
describe('Loads the app', () => {
|
||||||
it('renders the alerts tab', async () => {
|
before(async () => {
|
||||||
// Navigate to the alerts tab
|
await pageObjects.common.navigateToApp('triggersActions');
|
||||||
await pageObjects.triggersActionsUI.changeTabs('alertsTab');
|
|
||||||
|
|
||||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
|
||||||
|
|
||||||
// Verify url
|
|
||||||
const url = await browser.getCurrentUrl();
|
|
||||||
expect(url).to.contain(`/alerts`);
|
|
||||||
|
|
||||||
// Verify content
|
|
||||||
await testSubjects.existOrFail('alertsList');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates to an alert details page', async () => {
|
after(async () => {
|
||||||
const { body: createdAction } = await supertest
|
await objectRemover.removeAll();
|
||||||
.post(`/api/actions/action`)
|
});
|
||||||
.set('kbn-xsrf', 'foo')
|
|
||||||
.send(getTestActionData())
|
|
||||||
.expect(200);
|
|
||||||
objectRemover.add(createdAction.id, 'action', 'actions');
|
|
||||||
|
|
||||||
const { body: createdAlert } = await supertest
|
it('Loads the Alerts page', async () => {
|
||||||
.post(`/api/alerts/alert`)
|
await log.debug('Checking for section heading to say Triggers and Actions.');
|
||||||
.set('kbn-xsrf', 'foo')
|
|
||||||
.send(getTestAlertData())
|
|
||||||
.expect(200);
|
|
||||||
objectRemover.add(createdAlert.id, 'alert', 'alerts');
|
|
||||||
|
|
||||||
// refresh to see alert
|
const headingText = await pageObjects.triggersActionsUI.getSectionHeadingText();
|
||||||
await browser.refresh();
|
expect(headingText).to.be('Alerts and Actions');
|
||||||
|
});
|
||||||
|
|
||||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
describe('Connectors tab', () => {
|
||||||
|
it('renders the connectors tab', async () => {
|
||||||
|
// Navigate to the connectors tab
|
||||||
|
await pageObjects.triggersActionsUI.changeTabs('connectorsTab');
|
||||||
|
|
||||||
// Verify content
|
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||||
await testSubjects.existOrFail('alertsList');
|
|
||||||
|
|
||||||
// click on first alert
|
// Verify url
|
||||||
await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(createdAlert.name);
|
const url = await browser.getCurrentUrl();
|
||||||
|
expect(url).to.contain(`/connectors`);
|
||||||
|
|
||||||
// Verify url
|
// Verify content
|
||||||
expect(await browser.getCurrentUrl()).to.contain(`/alert/${createdAlert.id}`);
|
await testSubjects.existOrFail('actionsList');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Alerts tab', () => {
|
||||||
|
it('renders the alerts tab', async () => {
|
||||||
|
// Navigate to the alerts tab
|
||||||
|
await pageObjects.triggersActionsUI.changeTabs('alertsTab');
|
||||||
|
|
||||||
|
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||||
|
|
||||||
|
// Verify url
|
||||||
|
const url = await browser.getCurrentUrl();
|
||||||
|
expect(url).to.contain(`/alerts`);
|
||||||
|
|
||||||
|
// Verify content
|
||||||
|
await testSubjects.existOrFail('alertsList');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('navigates to an alert details page', async () => {
|
||||||
|
const { body: createdAction } = await supertest
|
||||||
|
.post(`/api/actions/action`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestActionData())
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add(createdAction.id, 'action', 'actions');
|
||||||
|
|
||||||
|
const { body: createdAlert } = await supertest
|
||||||
|
.post(`/api/alerts/alert`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestAlertData())
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add(createdAlert.id, 'alert', 'alerts');
|
||||||
|
|
||||||
|
// refresh to see alert
|
||||||
|
await browser.refresh();
|
||||||
|
|
||||||
|
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||||
|
|
||||||
|
// Verify content
|
||||||
|
await testSubjects.existOrFail('alertsList');
|
||||||
|
|
||||||
|
// click on first alert
|
||||||
|
await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(createdAlert.name);
|
||||||
|
|
||||||
|
// Verify url
|
||||||
|
expect(await browser.getCurrentUrl()).to.contain(`/alert/${createdAlert.id}`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -86,6 +86,22 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||||
})}`,
|
})}`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
security: {
|
||||||
|
roles: {
|
||||||
|
alerts_and_actions_role: {
|
||||||
|
kibana: [
|
||||||
|
{
|
||||||
|
feature: {
|
||||||
|
actions: ['all'],
|
||||||
|
stackAlerts: ['all'],
|
||||||
|
},
|
||||||
|
spaces: ['*'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultRoles: ['superuser'],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return returnedObject;
|
return returnedObject;
|
||||||
|
|
Loading…
Reference in a new issue