diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts index 86689c03ab96b..cd919f0725a23 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts @@ -87,6 +87,7 @@ describe(`feature_privilege_builder`, () => { "alerting:alert-type/my-feature/rule/getRuleState", "alerting:alert-type/my-feature/rule/getAlertSummary", "alerting:alert-type/my-feature/rule/getExecutionLog", + "alerting:alert-type/my-feature/rule/getActionErrorLog", "alerting:alert-type/my-feature/rule/find", "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", "alerting:alert-type/my-feature/rule/runSoon", @@ -174,6 +175,7 @@ describe(`feature_privilege_builder`, () => { "alerting:alert-type/my-feature/rule/getRuleState", "alerting:alert-type/my-feature/rule/getAlertSummary", "alerting:alert-type/my-feature/rule/getExecutionLog", + "alerting:alert-type/my-feature/rule/getActionErrorLog", "alerting:alert-type/my-feature/rule/find", "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", "alerting:alert-type/my-feature/rule/runSoon", @@ -221,6 +223,7 @@ describe(`feature_privilege_builder`, () => { "alerting:alert-type/my-feature/rule/getRuleState", "alerting:alert-type/my-feature/rule/getAlertSummary", "alerting:alert-type/my-feature/rule/getExecutionLog", + "alerting:alert-type/my-feature/rule/getActionErrorLog", "alerting:alert-type/my-feature/rule/find", "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", "alerting:alert-type/my-feature/rule/runSoon", @@ -325,6 +328,7 @@ describe(`feature_privilege_builder`, () => { "alerting:alert-type/my-feature/rule/getRuleState", "alerting:alert-type/my-feature/rule/getAlertSummary", "alerting:alert-type/my-feature/rule/getExecutionLog", + "alerting:alert-type/my-feature/rule/getActionErrorLog", "alerting:alert-type/my-feature/rule/find", "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", "alerting:alert-type/my-feature/rule/runSoon", @@ -389,6 +393,7 @@ describe(`feature_privilege_builder`, () => { "alerting:alert-type/my-feature/rule/getRuleState", "alerting:alert-type/my-feature/rule/getAlertSummary", "alerting:alert-type/my-feature/rule/getExecutionLog", + "alerting:alert-type/my-feature/rule/getActionErrorLog", "alerting:alert-type/my-feature/rule/find", "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", "alerting:alert-type/my-feature/rule/runSoon", @@ -412,6 +417,7 @@ describe(`feature_privilege_builder`, () => { "alerting:readonly-alert-type/my-feature/rule/getRuleState", "alerting:readonly-alert-type/my-feature/rule/getAlertSummary", "alerting:readonly-alert-type/my-feature/rule/getExecutionLog", + "alerting:readonly-alert-type/my-feature/rule/getActionErrorLog", "alerting:readonly-alert-type/my-feature/rule/find", "alerting:readonly-alert-type/my-feature/rule/getRuleExecutionKPI", "alerting:readonly-alert-type/my-feature/rule/runSoon", @@ -504,6 +510,7 @@ describe(`feature_privilege_builder`, () => { "alerting:alert-type/my-feature/rule/getRuleState", "alerting:alert-type/my-feature/rule/getAlertSummary", "alerting:alert-type/my-feature/rule/getExecutionLog", + "alerting:alert-type/my-feature/rule/getActionErrorLog", "alerting:alert-type/my-feature/rule/find", "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", "alerting:alert-type/my-feature/rule/runSoon", @@ -527,6 +534,7 @@ describe(`feature_privilege_builder`, () => { "alerting:readonly-alert-type/my-feature/rule/getRuleState", "alerting:readonly-alert-type/my-feature/rule/getAlertSummary", "alerting:readonly-alert-type/my-feature/rule/getExecutionLog", + "alerting:readonly-alert-type/my-feature/rule/getActionErrorLog", "alerting:readonly-alert-type/my-feature/rule/find", "alerting:readonly-alert-type/my-feature/rule/getRuleExecutionKPI", "alerting:readonly-alert-type/my-feature/rule/runSoon", diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts index 612981c9ffb0c..871b1cfee169e 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts @@ -22,6 +22,7 @@ const readOperations: Record = { 'getRuleState', 'getAlertSummary', 'getExecutionLog', + 'getActionErrorLog', 'find', 'getRuleExecutionKPI', 'runSoon', diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_action_error_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_action_error_log.ts index c2e4084fd195c..754adcc6c9ae2 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_action_error_log.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_action_error_log.ts @@ -8,13 +8,20 @@ import expect from '@kbn/expect'; import { ESTestIndexTool } from '@kbn/alerting-api-integration-helpers'; -import { Spaces } from '../../../scenarios'; -import { getUrlPrefix, ObjectRemover, getTestRuleData, getEventLog } from '../../../../common/lib'; +import { Spaces, UserAtSpaceScenarios } from '../../../scenarios'; +import { + getUrlPrefix, + ObjectRemover, + getTestRuleData, + getEventLog, + getConsumerUnauthorizedErrorMessage, +} from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function createGetActionErrorLogTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); const retry = getService('retry'); const es = getService('es'); const esTestIndexTool = new ESTestIndexTool(es, retry); @@ -33,6 +40,98 @@ export default function createGetActionErrorLogTests({ getService }: FtrProvider await objectRemover.removeAll(); }); + for (const scenario of UserAtSpaceScenarios) { + const { user, space } = scenario; + describe(scenario.id, () => { + it('gets action error logs for rules with action errors with appropriate authorization', async () => { + const { body: createdConnector } = await supertest + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'connector that throws', + connector_type_id: 'test.throw', + config: {}, + secrets: {}, + }) + .expect(200); + objectRemover.add(space.id, createdConnector.id, 'action', 'actions'); + + const { body: createdRule } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.cumulative-firing', + actions: [ + { + id: createdConnector.id, + group: 'default', + params: {}, + }, + ], + }) + ) + .expect(200); + objectRemover.add(space.id, createdRule.id, 'rule', 'alerting'); + + await waitForEvents( + createdRule.id, + 'alerting', + new Map([['execute', { gte: 1 }]]), + space.id + ); + await waitForEvents( + createdRule.id, + 'actions', + new Map([['execute', { gte: 1 }]]), + space.id + ); + + const response = await supertestWithoutAuth + .get( + `${getUrlPrefix(space.id)}/internal/alerting/rule/${ + createdRule.id + }/_action_error_log?date_start=${dateStart}` + ) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(403); + expect(response.body).to.eql({ + error: 'Forbidden', + message: getConsumerUnauthorizedErrorMessage( + 'get', + 'test.cumulative-firing', + 'alertsFixture' + ), + statusCode: 403, + }); + break; + case 'global_read at space1': + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(200); + expect(response.body.totalErrors).to.eql(1); + expect(response.body.errors.length).to.eql(1); + + for (const errors of response.body.errors) { + expect(errors.type).to.equal('actions'); + expect(errors.message).to.equal( + `action execution failure: test.throw:${createdConnector.id}: connector that throws - an error occurred while running the action: this action is intended to fail; retry: true` + ); + } + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + }); + } + it('gets action error logs from an alternate space', async () => { const { body: createdConnector } = await supertest .post(`${getUrlPrefix(Spaces[1].id)}/api/actions/connector`) @@ -99,12 +198,13 @@ export default function createGetActionErrorLogTests({ getService }: FtrProvider { gte: number; } - > + >, + spaceId = Spaces[1].id ) { await retry.try(async () => { return await getEventLog({ getService, - spaceId: Spaces[1].id, + spaceId, type: 'alert', id, provider,