import expect from '@kbn/expect' ; import { UserAtSpaceScenarios , Superuser } from '../../scenarios' ; import { FtrProviderContext } from '../../../common/ftr_provider_context' ; import { ESTestIndexTool , getUrlPrefix , ObjectRemover , AlertUtils } from '../../../common/lib' ; import { setupSpacesAndUsers } from '..' ; import { SavedObjectsUtils } from '../../../../../../src/core/server/saved_objects' ; export default function alertTests ( { getService } ) { const supertest = getService ( 'supertest' ) ; const es = getService ( 'es' ) ; const retry = getService ( 'retry' ) ; const esArchiver = getService ( 'esArchiver' ) ; const supertestWithoutAuth = getService ( 'supertestWithoutAuth' ) ; const esTestIndexTool = new ESTestIndexTool ( es , retry ) ; const MIGRATED_ACTION_ID = SavedObjectsUtils . getConvertedObjectId ( 'space1' , 'action' , '17f38826-5a8d-4a76-975a-b496e7fffe0b' ) ; const MIGRATED_ALERT_ID = { space_1_all_alerts_none_actions : SavedObjectsUtils . getConvertedObjectId ( 'space1' , 'alert' , '6ee9630a-a20e-44af-9465-217a3717d2ab' ) , space_1_all_with_restricted_fixture : SavedObjectsUtils . getConvertedObjectId ( 'space1' , 'alert' , '5cc59319-74ee-4edc-8646-a79ea91067cd' ) , space_1_all : SavedObjectsUtils . getConvertedObjectId ( 'space1' , 'alert' , 'd41a6abb-b93b-46df-a80a-926221ea847c' ) , global_read : SavedObjectsUtils . getConvertedObjectId ( 'space1' , 'alert' , '362e362b-a137-4aa2-9434-43e3d0d84a34' ) , superuser : SavedObjectsUtils . getConvertedObjectId ( 'space1' , 'alert' , 'b384be60-ec53-4b26-857e-0253ee55b277' ) , } ; describe ( 'alerts' , ( ) => { const authorizationIndex = '.kibana-test-authorization' ; const objectRemover = new ObjectRemover ( supertest ) ; before ( async ( ) => { await esTestIndexTool . destroy ( ) ; await esArchiver . load ( 'x-pack/test/functional/es_archives/alerts_legacy' ) ; await esTestIndexTool . setup ( ) ; await es . indices . create ( { index : authorizationIndex } ) ; await setupSpacesAndUsers ( getService ) ; } ) ; after ( async ( ) => { await esTestIndexTool . destroy ( ) ; await es . indices . delete ( { index : authorizationIndex } ) ; await esArchiver . unload ( 'x-pack/test/functional/es_archives/alerts_legacy' ) ; } ) ; for ( const scenario of UserAtSpaceScenarios ) { const { user , space } = scenario ; describe ( scenario . id , ( ) => { let alertUtils ; before ( async ( ) => { alertUtils = new AlertUtils ( { user , space , supertestWithoutAuth , indexRecordActionId : MIGRATED_ACTION_ID , objectRemover , } ) ; } ) ; it ( 'should schedule actions on legacy alerts' , async ( ) => { const reference = `alert:migrated-to-7.10:${ user . username }` ; const migratedAlertId = MIGRATED_ALERT_ID [ user . username ] ; switch ( scenario . id ) { case 'no_kibana_privileges at space1' : case 'space_1_all at space2' : break ; case 'space_1_all at space1' : case 'superuser at space1' : case 'space_1_all_with_restricted_fixture at space1' : await resetTaskStatus ( migratedAlertId ) ; await ensureLegacyAlertHasBeenMigrated ( migratedAlertId ) ; await updateMigratedAlertToUseApiKeyOfCurrentUser ( migratedAlertId ) ; await ensureAlertIsRunning ( ) ; await updateAlertSoThatItIsNoLongerLegacy ( migratedAlertId ) ; const updatedKeyResponse = await alertUtils . getUpdateApiKeyRequest ( migratedAlertId ) ; expect ( updatedKeyResponse . statusCode ) . to . eql ( 204 ) ; await ensureAlertIsRunning ( ) ; break ; case 'global_read at space1' : await resetTaskStatus ( migratedAlertId ) ; await ensureLegacyAlertHasBeenMigrated ( migratedAlertId ) ; await updateMigratedAlertToUseApiKeyOfCurrentUser ( migratedAlertId ) ; await ensureAlertIsRunning ( ) ; await updateAlertSoThatItIsNoLongerLegacy ( migratedAlertId ) ; const failedUpdateKeyDueToAlertsPrivilegesResponse = await alertUtils . getUpdateApiKeyRequest ( migratedAlertId ) ; expect ( failedUpdateKeyDueToAlertsPrivilegesResponse . statusCode ) . to . eql ( 403 ) ; expect ( failedUpdateKeyDueToAlertsPrivilegesResponse . body ) . to . eql ( { error : 'Forbidden' , message : 'Unauthorized to updateApiKey a "test.always-firing" rule for "alertsFixture"' , statusCode : 403 , } ) ; break ; case 'space_1_all_alerts_none_actions at space1' : await resetTaskStatus ( migratedAlertId ) ; await ensureLegacyAlertHasBeenMigrated ( migratedAlertId ) ; await updateMigratedAlertToUseApiKeyOfCurrentUser ( migratedAlertId ) ; await ensureAlertIsRunning ( ) ; await updateAlertSoThatItIsNoLongerLegacy ( migratedAlertId ) ; const failedUpdateKeyDueToActionsPrivilegesResponse = await alertUtils . getUpdateApiKeyRequest ( migratedAlertId ) ; expect ( failedUpdateKeyDueToActionsPrivilegesResponse . statusCode ) . to . eql ( 403 ) ; expect ( failedUpdateKeyDueToActionsPrivilegesResponse . body ) . to . eql ( { error : 'Forbidden' , message : 'Unauthorized to execute actions' , statusCode : 403 , } ) ; break ; default : throw new Error ( `Scenario untested: ${ JSON . stringify ( scenario ) }` ) ; } async function resetTaskStatus ( alertId ) { await supertest . put ( `${ getUrlPrefix ( space . id ) }/api/alerts_fixture/${ alertId }/reset_task_status` ) . set ( 'kbn-xsrf' , 'foo' ) . send ( { status : 'idle' , } ) . expect ( 200 ) ; } async function ensureLegacyAlertHasBeenMigrated ( alertId ) { const getResponse = await supertestWithoutAuth . get ( `${ getUrlPrefix ( space . id ) }/api/alerting/rule/${ alertId }` ) . auth ( user . username , user . password ) ; expect ( getResponse . status ) . to . eql ( 200 ) ; } async function updateMigratedAlertToUseApiKeyOfCurrentUser ( alertId ) { const swapResponse = await alertUtils . replaceApiKeys ( alertId ) ; expect ( swapResponse . statusCode ) . to . eql ( 200 ) ; expect ( swapResponse . body . id ) . to . eql ( alertId ) ; expect ( swapResponse . body . attributes . meta . versionApiKeyLastmodified ) . to . eql ( 'pre-7.10.0' ) ; const getResponse = await supertestWithoutAuth . get ( `${ getUrlPrefix ( space . id ) }/api/alerting/rule/${ alertId }` ) . auth ( user . username , user . password ) . expect ( 200 ) ; await supertest . put ( `${ getUrlPrefix ( space . id ) }/api/alerts_fixture/${ getResponse . body . scheduled_task_id }/reschedule_task` ) . set ( 'kbn-xsrf' , 'foo' ) . send ( { runAt : getRunAt ( 2000 ) , } ) . expect ( 200 ) ; } async function ensureAlertIsRunning ( ) { const alwaysFiringResponse = await esTestIndexTool . search ( 'alert:test.always-firing' , reference ) ; const numberOfAlertExecutions = alwaysFiringResponse . body . hits . total . value ; const indexRecordResponse = await esTestIndexTool . search ( 'action:test.index-record' , reference ) ; const numberOfActionExecutions = indexRecordResponse . body . hits . total . value ; await retry . try ( async ( ) => { const alertSearchResult = await esTestIndexTool . search ( 'alert:test.always-firing' , reference ) ; const actionSearchResult = await esTestIndexTool . search ( 'action:test.index-record' , reference ) ; expect ( alertSearchResult . body . hits . total . value ) . to . be . greaterThan ( numberOfAlertExecutions ) ; expect ( actionSearchResult . body . hits . total . value ) . to . be . greaterThan ( numberOfActionExecutions ) ; } ) ; } async function updateAlertSoThatItIsNoLongerLegacy ( alertId ) { await alertUtils . updateAlwaysFiringAction ( { alertId , actionId : MIGRATED_ACTION_ID , user : Superuser , reference , overwrites : { name : 'Updated Alert' , schedule : { interval : '2s' } , throttle : '2s' , } , } ) ; } } ) ; } ) ; } } ) ; } function getRunAt ( delayInMs ) { const runAt = new Date ( ) ; runAt . setMilliseconds ( new Date ( ) . getMilliseconds ( ) + delayInMs ) ; return runAt . toISOString ( ) ; }