From c05588f0770746f171fd6b1d5bb75b1246ec014c Mon Sep 17 00:00:00 2001 From: ymao1 Date: Mon, 28 Jun 2021 20:35:27 -0400 Subject: [PATCH] [Alerting] Enable rule import/export and allow rule types to exclude themselves from export (#102999) * Removing feature flag changes * Adding isExportable flag to rule type definition * Adding isExportable flag to rule type definition * Adding isExportable flag to rule type definition * Filtering rule on export by rule type isExportable flag * Fixing types * Adding docs * Fix condition when exportCount is 0 * Unit test for fix condition when exportCount is 0 Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/api/alerting/legacy/list.asciidoc | 4 + docs/api/alerting/list_rule_types.asciidoc | 4 + .../alerting/create-and-manage-rules.asciidoc | 19 ++ .../server/saved_objects/routes/utils.test.ts | 16 ++ src/core/server/saved_objects/routes/utils.ts | 2 +- .../server/alert_types/always_firing.ts | 1 + .../server/alert_types/astros.ts | 1 + x-pack/plugins/alerting/README.md | 2 + x-pack/plugins/alerting/common/alert_type.ts | 1 + .../plugins/alerting/public/alert_api.test.ts | 3 + .../alert_navigation_registry.test.ts | 1 + .../server/alert_type_registry.test.ts | 16 ++ .../alerting/server/alert_type_registry.ts | 3 + .../alerts_client/tests/aggregate.test.ts | 2 + .../server/alerts_client/tests/create.test.ts | 1 + .../server/alerts_client/tests/find.test.ts | 2 + .../server/alerts_client/tests/lib.ts | 1 + .../tests/list_alert_types.test.ts | 5 + .../server/alerts_client/tests/update.test.ts | 3 + .../alerts_client_conflict_retries.test.ts | 2 + .../alerting_authorization.test.ts | 18 ++ .../alerting_authorization_kuery.test.ts | 10 + x-pack/plugins/alerting/server/config.test.ts | 1 - x-pack/plugins/alerting/server/config.ts | 1 - .../alerting/server/health/get_state.test.ts | 8 - .../alerting/server/lib/license_state.test.ts | 2 + x-pack/plugins/alerting/server/plugin.test.ts | 72 +----- x-pack/plugins/alerting/server/plugin.ts | 9 +- .../routes/legacy/list_alert_types.test.ts | 4 + .../alerting/server/routes/rule_types.test.ts | 5 + .../alerting/server/routes/rule_types.ts | 2 + .../alerting/server/saved_objects/index.ts | 111 +++++----- .../saved_objects/is_rule_exportable.test.ts | 208 ++++++++++++++++++ .../saved_objects/is_rule_exportable.ts | 33 +++ .../create_execution_handler.test.ts | 1 + .../server/task_runner/task_runner.test.ts | 1 + .../task_runner/task_runner_factory.test.ts | 1 + x-pack/plugins/alerting/server/types.ts | 1 + x-pack/plugins/apm/common/alert_types.ts | 5 + .../alerts/register_error_count_alert_type.ts | 1 + ...egister_transaction_duration_alert_type.ts | 1 + ...transaction_duration_anomaly_alert_type.ts | 1 + ...ister_transaction_error_rate_alert_type.ts | 1 + ...r_inventory_metric_threshold_alert_type.ts | 1 + .../register_log_threshold_alert_type.ts | 1 + .../register_metric_anomaly_alert_type.ts | 1 + .../register_metric_threshold_alert_type.ts | 1 + .../register_anomaly_detection_alert_type.ts | 1 + .../monitoring/server/alerts/base_alert.ts | 1 + .../utils/create_lifecycle_rule_type.test.ts | 1 + .../rules_notification_alert_type.ts | 1 + .../detection_engine/reference_rules/eql.ts | 1 + .../detection_engine/reference_rules/ml.ts | 1 + .../detection_engine/reference_rules/query.ts | 1 + .../reference_rules/threshold.ts | 1 + .../signals/signal_rule_alert_type.ts | 1 + .../server/alert_types/es_query/alert_type.ts | 1 + .../alert_types/geo_containment/alert_type.ts | 1 + .../alert_types/index_threshold/alert_type.ts | 1 + .../server/lib/alerts/duration_anomaly.ts | 1 + .../uptime/server/lib/alerts/status_check.ts | 1 + .../plugins/uptime/server/lib/alerts/tls.ts | 1 + .../uptime/server/lib/alerts/tls_legacy.ts | 1 + .../plugins/alerts/server/alert_types.ts | 13 ++ .../alerts_restricted/server/alert_types.ts | 2 + .../tests/alerting/rule_types.ts | 2 + .../spaces_only/tests/alerting/rule_types.ts | 2 + .../fixtures/plugins/alerts/server/plugin.ts | 3 + 68 files changed, 489 insertions(+), 139 deletions(-) create mode 100644 x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts create mode 100644 x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.ts diff --git a/docs/api/alerting/legacy/list.asciidoc b/docs/api/alerting/legacy/list.asciidoc index be37be36cd0e8..07307797c4223 100644 --- a/docs/api/alerting/legacy/list.asciidoc +++ b/docs/api/alerting/legacy/list.asciidoc @@ -80,6 +80,7 @@ The API returns the following: }, "producer":"stackAlerts", "minimumLicenseRequired":"basic", + "isExportable":true, "enabledInLicense":true, "authorizedConsumers":{ "alerts":{ @@ -113,6 +114,9 @@ Each alert type contains the following properties: | `minimumLicenseRequired` | The license required to use the alert type. +| `isExportable` +| Whether the rule type is exportable through the Saved Objects Management UI. + | `enabledInLicense` | Whether the alert type is enabled or disabled based on the license. diff --git a/docs/api/alerting/list_rule_types.asciidoc b/docs/api/alerting/list_rule_types.asciidoc index 31c8416e75059..21ace9f3105c0 100644 --- a/docs/api/alerting/list_rule_types.asciidoc +++ b/docs/api/alerting/list_rule_types.asciidoc @@ -82,6 +82,7 @@ The API returns the following: }, "producer":"stackAlerts", "minimum_license_required":"basic", + "is_exportable":true, "enabled_in_license":true, "authorized_consumers":{ "alerts":{ @@ -115,6 +116,9 @@ Each rule type contains the following properties: | `minimum_license_required` | The license required to use the rule type. +| `is_exportable` +| Whether the rule type is exportable through the Saved Objects Management UI. + | `enabled_in_license` | Whether the rule type is enabled or disabled based on the license. diff --git a/docs/user/alerting/create-and-manage-rules.asciidoc b/docs/user/alerting/create-and-manage-rules.asciidoc index af6714aef662f..cc91ebcd99be2 100644 --- a/docs/user/alerting/create-and-manage-rules.asciidoc +++ b/docs/user/alerting/create-and-manage-rules.asciidoc @@ -152,6 +152,25 @@ You can perform these operations in bulk by multi-selecting rules, and then clic [role="screenshot"] image:images/bulk-mute-disable.png[The Manage rules button lets you mute/unmute, enable/disable, and delete in bulk,width=75%] +[float] +[[importing-and-exporting-rules]] +=== Import and export rules + +To import and export rules, use the <>. + +[NOTE] +============================================== +Some rule types cannot be exported through this interface: + +**Security rules** can be imported and exported using the {security-guide}/rules-ui-management.html#import-export-rules-ui[Security UI]. + +**Stack monitoring rules** are <> for you and therefore cannot be managed via the Saved Objects Management UI. +============================================== + +Rules are disabled on export. You are prompted to re-enable rule on successful import. +[role="screenshot"] +image::images/rules-imported-banner.png[Rules import banner, width=50%] + [float] [[rule-details]] === Drilldown to rule details diff --git a/src/core/server/saved_objects/routes/utils.test.ts b/src/core/server/saved_objects/routes/utils.test.ts index 623d2dcc71fac..2127352e4c60e 100644 --- a/src/core/server/saved_objects/routes/utils.test.ts +++ b/src/core/server/saved_objects/routes/utils.test.ts @@ -101,6 +101,22 @@ describe('createSavedObjectsStreamFromNdJson', () => { }, ]); }); + + it('handles an ndjson stream that only contains excluded saved objects', async () => { + const savedObjectsStream = await createSavedObjectsStreamFromNdJson( + new Readable({ + read() { + this.push( + '{"excludedObjects":[{"id":"foo","reason":"excluded","type":"foo-type"}],"excludedObjectsCount":1,"exportedCount":0,"missingRefCount":0,"missingReferences":[]}\n' + ); + this.push(null); + }, + }) + ); + + const result = await readStreamToCompletion(savedObjectsStream); + expect(result).toEqual([]); + }); }); describe('validateTypes', () => { diff --git a/src/core/server/saved_objects/routes/utils.ts b/src/core/server/saved_objects/routes/utils.ts index e933badfe80fe..47996847a8387 100644 --- a/src/core/server/saved_objects/routes/utils.ts +++ b/src/core/server/saved_objects/routes/utils.ts @@ -32,7 +32,7 @@ export async function createSavedObjectsStreamFromNdJson(ndJsonStream: Readable) } }), createFilterStream( - (obj) => !!obj && !(obj as SavedObjectsExportResultDetails).exportedCount + (obj) => !!obj && (obj as SavedObjectsExportResultDetails).exportedCount === undefined ), createConcatStream([]), ]); diff --git a/x-pack/examples/alerting_example/server/alert_types/always_firing.ts b/x-pack/examples/alerting_example/server/alert_types/always_firing.ts index 6e9ec0d367c9a..f056c292b018f 100644 --- a/x-pack/examples/alerting_example/server/alert_types/always_firing.ts +++ b/x-pack/examples/alerting_example/server/alert_types/always_firing.ts @@ -53,6 +53,7 @@ export const alertType: AlertType< ], defaultActionGroupId: DEFAULT_ACTION_GROUP, minimumLicenseRequired: 'basic', + isExportable: true, async executor({ services, params: { instances = DEFAULT_INSTANCES_TO_GENERATE, thresholds }, diff --git a/x-pack/examples/alerting_example/server/alert_types/astros.ts b/x-pack/examples/alerting_example/server/alert_types/astros.ts index 45ea6b48bf6f4..8f9a293518300 100644 --- a/x-pack/examples/alerting_example/server/alert_types/astros.ts +++ b/x-pack/examples/alerting_example/server/alert_types/astros.ts @@ -51,6 +51,7 @@ export const alertType: AlertType< name: 'People In Space Right Now', actionGroups: [{ id: 'default', name: 'default' }], minimumLicenseRequired: 'basic', + isExportable: true, defaultActionGroupId: 'default', recoveryActionGroup: { id: 'hasLandedBackOnEarth', diff --git a/x-pack/plugins/alerting/README.md b/x-pack/plugins/alerting/README.md index 9d314cc048b70..62d2f2b57b8e8 100644 --- a/x-pack/plugins/alerting/README.md +++ b/x-pack/plugins/alerting/README.md @@ -118,6 +118,7 @@ The following table describes the properties of the `options` object. |executor|This is where the code for the rule type lives. This is a function to be called when executing a rule on an interval basis. For full details, see the executor section below.|Function| |producer|The id of the application producing this rule type.|string| |minimumLicenseRequired|The value of a minimum license. Most of the rules are licensed as "basic".|string| +|isExportable|Whether the rule type is exportable from the Saved Objects Management UI.|boolean| ### Executor @@ -262,6 +263,7 @@ const myRuleType: AlertType< ], }, minimumLicenseRequired: 'basic', + isExportable: true, async executor({ alertId, startedAt, diff --git a/x-pack/plugins/alerting/common/alert_type.ts b/x-pack/plugins/alerting/common/alert_type.ts index e39c6d0a66f6c..e56034a4c41f8 100644 --- a/x-pack/plugins/alerting/common/alert_type.ts +++ b/x-pack/plugins/alerting/common/alert_type.ts @@ -20,6 +20,7 @@ export interface AlertType< defaultActionGroupId: ActionGroupIds; producer: string; minimumLicenseRequired: LicenseType; + isExportable: boolean; } export interface ActionGroup { diff --git a/x-pack/plugins/alerting/public/alert_api.test.ts b/x-pack/plugins/alerting/public/alert_api.test.ts index 023ea255e1c42..dd2f7d167c1c3 100644 --- a/x-pack/plugins/alerting/public/alert_api.test.ts +++ b/x-pack/plugins/alerting/public/alert_api.test.ts @@ -24,6 +24,7 @@ describe('loadAlertTypes', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, producer: 'alerts', }, @@ -49,6 +50,7 @@ describe('loadAlertType', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, producer: 'alerts', }; @@ -71,6 +73,7 @@ describe('loadAlertType', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, producer: 'alerts', }; diff --git a/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts b/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts index 7eb5996311386..e7e311902d08d 100644 --- a/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts +++ b/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts @@ -20,6 +20,7 @@ const mockAlertType = (id: string): AlertType => ({ defaultActionGroupId: 'default', producer: 'alerts', minimumLicenseRequired: 'basic', + isExportable: true, }); describe('AlertNavigationRegistry', () => { diff --git a/x-pack/plugins/alerting/server/alert_type_registry.test.ts b/x-pack/plugins/alerting/server/alert_type_registry.test.ts index 7f34760c73199..63e381bc66c0a 100644 --- a/x-pack/plugins/alerting/server/alert_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/alert_type_registry.test.ts @@ -47,6 +47,7 @@ describe('has()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }); @@ -67,6 +68,7 @@ describe('register()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }; @@ -99,6 +101,7 @@ describe('register()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }; @@ -129,6 +132,7 @@ describe('register()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }; @@ -159,6 +163,7 @@ describe('register()', () => { executor: jest.fn(), producer: 'alerts', minimumLicenseRequired: 'basic', + isExportable: true, }; const registry = new AlertTypeRegistry(alertTypeRegistryParams); registry.register(alertType); @@ -203,6 +208,7 @@ describe('register()', () => { }, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }; @@ -227,6 +233,7 @@ describe('register()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }; @@ -257,6 +264,7 @@ describe('register()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }; @@ -279,6 +287,7 @@ describe('register()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }); @@ -294,6 +303,7 @@ describe('register()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }) @@ -315,6 +325,7 @@ describe('get()', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, executor: jest.fn(), producer: 'alerts', }); @@ -339,6 +350,7 @@ describe('get()', () => { "defaultActionGroupId": "default", "executor": [MockFunction], "id": "test", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "Test", "producer": "alerts", @@ -377,6 +389,7 @@ describe('list()', () => { }, ], defaultActionGroupId: 'testActionGroup', + isExportable: true, minimumLicenseRequired: 'basic', executor: jest.fn(), producer: 'alerts', @@ -403,6 +416,7 @@ describe('list()', () => { "defaultActionGroupId": "testActionGroup", "enabledInLicense": false, "id": "test", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "Test", "producer": "alerts", @@ -467,6 +481,7 @@ describe('ensureAlertTypeEnabled', () => { defaultActionGroupId: 'default', executor: jest.fn(), producer: 'alerts', + isExportable: true, minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, }); @@ -497,6 +512,7 @@ function alertTypeWithVariables( name: `${id}-name`, actionGroups: [], defaultActionGroupId: id, + isExportable: true, minimumLicenseRequired: 'basic', async executor() {}, producer: 'alerts', diff --git a/x-pack/plugins/alerting/server/alert_type_registry.ts b/x-pack/plugins/alerting/server/alert_type_registry.ts index 21feb76926791..64fca58c25e66 100644 --- a/x-pack/plugins/alerting/server/alert_type_registry.ts +++ b/x-pack/plugins/alerting/server/alert_type_registry.ts @@ -46,6 +46,7 @@ export interface RegistryAlertType | 'actionVariables' | 'producer' | 'minimumLicenseRequired' + | 'isExportable' > { id: string; enabledInLicense: boolean; @@ -250,6 +251,7 @@ export class AlertTypeRegistry { actionVariables, producer, minimumLicenseRequired, + isExportable, }, ]: [string, UntypedNormalizedAlertType]) => ({ id, @@ -260,6 +262,7 @@ export class AlertTypeRegistry { actionVariables, producer, minimumLicenseRequired, + isExportable, enabledInLicense: !!this.licenseState.getLicenseCheckForAlertType( id, name, diff --git a/x-pack/plugins/alerting/server/alerts_client/tests/aggregate.test.ts b/x-pack/plugins/alerting/server/alerts_client/tests/aggregate.test.ts index bf966d38f6bc6..611ff23e46256 100644 --- a/x-pack/plugins/alerting/server/alerts_client/tests/aggregate.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/tests/aggregate.test.ts @@ -58,6 +58,7 @@ describe('aggregate()', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myType', name: 'myType', @@ -110,6 +111,7 @@ describe('aggregate()', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, producer: 'alerts', authorizedConsumers: { diff --git a/x-pack/plugins/alerting/server/alerts_client/tests/create.test.ts b/x-pack/plugins/alerting/server/alerts_client/tests/create.test.ts index 793357215d382..e231d1e3c27a2 100644 --- a/x-pack/plugins/alerting/server/alerts_client/tests/create.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/tests/create.test.ts @@ -1293,6 +1293,7 @@ describe('create()', () => { }), }, minimumLicenseRequired: 'basic', + isExportable: true, async executor() {}, producer: 'alerts', }); diff --git a/x-pack/plugins/alerting/server/alerts_client/tests/find.test.ts b/x-pack/plugins/alerting/server/alerts_client/tests/find.test.ts index fe788cd43bc2b..5ec39681a758b 100644 --- a/x-pack/plugins/alerting/server/alerts_client/tests/find.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/tests/find.test.ts @@ -67,6 +67,7 @@ describe('find()', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, id: 'myType', name: 'myType', producer: 'myApp', @@ -126,6 +127,7 @@ describe('find()', () => { recoveryActionGroup: RecoveredActionGroup, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, producer: 'alerts', authorizedConsumers: { myApp: { read: true, all: true }, diff --git a/x-pack/plugins/alerting/server/alerts_client/tests/lib.ts b/x-pack/plugins/alerting/server/alerts_client/tests/lib.ts index e4cd24ca7e49a..e0f4f9f6da0f1 100644 --- a/x-pack/plugins/alerting/server/alerts_client/tests/lib.ts +++ b/x-pack/plugins/alerting/server/alerts_client/tests/lib.ts @@ -88,6 +88,7 @@ export function getBeforeSetup( recoveryActionGroup: RecoveredActionGroup, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor() {}, producer: 'alerts', })); diff --git a/x-pack/plugins/alerting/server/alerts_client/tests/list_alert_types.test.ts b/x-pack/plugins/alerting/server/alerts_client/tests/list_alert_types.test.ts index 9fe33996b9edf..0f849423409d8 100644 --- a/x-pack/plugins/alerting/server/alerts_client/tests/list_alert_types.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/tests/list_alert_types.test.ts @@ -58,6 +58,7 @@ describe('listAlertTypes', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'alertingAlertType', name: 'alertingAlertType', @@ -69,6 +70,7 @@ describe('listAlertTypes', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myAppAlertType', name: 'myAppAlertType', @@ -110,6 +112,7 @@ describe('listAlertTypes', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myType', name: 'myType', @@ -122,6 +125,7 @@ describe('listAlertTypes', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, producer: 'alerts', enabledInLicense: true, @@ -139,6 +143,7 @@ describe('listAlertTypes', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, producer: 'alerts', authorizedConsumers: { diff --git a/x-pack/plugins/alerting/server/alerts_client/tests/update.test.ts b/x-pack/plugins/alerting/server/alerts_client/tests/update.test.ts index 350c9ed31298f..2de56d20702f4 100644 --- a/x-pack/plugins/alerting/server/alerts_client/tests/update.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/tests/update.test.ts @@ -127,6 +127,7 @@ describe('update()', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, async executor() {}, producer: 'alerts', @@ -773,6 +774,7 @@ describe('update()', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, validate: { params: schema.object({ @@ -1096,6 +1098,7 @@ describe('update()', () => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, async executor() {}, producer: 'alerts', diff --git a/x-pack/plugins/alerting/server/alerts_client_conflict_retries.test.ts b/x-pack/plugins/alerting/server/alerts_client_conflict_retries.test.ts index 98ad427d0c37b..e45b3513eef26 100644 --- a/x-pack/plugins/alerting/server/alerts_client_conflict_retries.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client_conflict_retries.test.ts @@ -335,6 +335,7 @@ beforeEach(() => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, async executor() {}, producer: 'alerts', @@ -346,6 +347,7 @@ beforeEach(() => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, async executor() {}, producer: 'alerts', diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts index 2227e0cecd0a6..c07148f03c684 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts @@ -203,6 +203,7 @@ beforeEach(() => { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, async executor() {}, producer: 'myApp', @@ -892,6 +893,7 @@ describe('AlertingAuthorization', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myOtherAppAlertType', name: 'myOtherAppAlertType', @@ -903,6 +905,7 @@ describe('AlertingAuthorization', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myAppAlertType', name: 'myAppAlertType', @@ -914,6 +917,7 @@ describe('AlertingAuthorization', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'mySecondAppAlertType', name: 'mySecondAppAlertType', @@ -1242,6 +1246,7 @@ describe('AlertingAuthorization', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myOtherAppAlertType', name: 'myOtherAppAlertType', @@ -1253,6 +1258,7 @@ describe('AlertingAuthorization', () => { actionVariables: undefined, defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myAppAlertType', name: 'myAppAlertType', @@ -1300,6 +1306,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myAppAlertType", "producer": "myApp", @@ -1328,6 +1335,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myOtherAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myOtherAppAlertType", "producer": "myOtherApp", @@ -1387,6 +1395,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myAppAlertType", "producer": "myApp", @@ -1423,6 +1432,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myOtherAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myOtherAppAlertType", "producer": "myOtherApp", @@ -1502,6 +1512,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myOtherAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myOtherAppAlertType", "producer": "myOtherApp", @@ -1526,6 +1537,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myAppAlertType", "producer": "myApp", @@ -1605,6 +1617,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myOtherAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myOtherAppAlertType", "producer": "myOtherApp", @@ -1633,6 +1646,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myAppAlertType", "producer": "myApp", @@ -1703,6 +1717,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myAppAlertType", "producer": "myApp", @@ -1807,6 +1822,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myOtherAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myOtherAppAlertType", "producer": "myOtherApp", @@ -1831,6 +1847,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myAppAlertType", "producer": "myApp", @@ -1914,6 +1931,7 @@ describe('AlertingAuthorization', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "myOtherAppAlertType", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "myOtherAppAlertType", "producer": "myOtherApp", diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts index 8a558b6427383..7d39380f7bd1a 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts @@ -26,6 +26,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => { name: 'myAppAlertType', producer: 'myApp', minimumLicenseRequired: 'basic', + isExportable: true, authorizedConsumers: { myApp: { read: true, all: true }, }, @@ -53,6 +54,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => { actionGroups: [], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myAppAlertType', name: 'myAppAlertType', @@ -88,6 +90,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => { actionGroups: [], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myAppAlertType', name: 'myAppAlertType', @@ -104,6 +107,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => { actionGroups: [], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myOtherAppAlertType', name: 'myOtherAppAlertType', @@ -120,6 +124,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => { actionGroups: [], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'mySecondAppAlertType', name: 'mySecondAppAlertType', @@ -162,6 +167,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { name: 'myAppAlertType', producer: 'myApp', minimumLicenseRequired: 'basic', + isExportable: true, authorizedConsumers: { myApp: { read: true, all: true }, }, @@ -216,6 +222,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { actionGroups: [], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myAppAlertType', name: 'myAppAlertType', @@ -283,6 +290,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { actionGroups: [], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myAppAlertType', name: 'myAppAlertType', @@ -299,6 +307,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { actionGroups: [], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'myOtherAppAlertType', name: 'myOtherAppAlertType', @@ -315,6 +324,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { actionGroups: [], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, id: 'mySecondAppAlertType', name: 'mySecondAppAlertType', diff --git a/x-pack/plugins/alerting/server/config.test.ts b/x-pack/plugins/alerting/server/config.test.ts index a8befe5210752..f7280e05b78f3 100644 --- a/x-pack/plugins/alerting/server/config.test.ts +++ b/x-pack/plugins/alerting/server/config.test.ts @@ -12,7 +12,6 @@ describe('config validation', () => { const config: Record = {}; expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { - "enableImportExport": false, "healthCheck": Object { "interval": "60m", }, diff --git a/x-pack/plugins/alerting/server/config.ts b/x-pack/plugins/alerting/server/config.ts index d50917fd13578..e42955b385bf1 100644 --- a/x-pack/plugins/alerting/server/config.ts +++ b/x-pack/plugins/alerting/server/config.ts @@ -16,7 +16,6 @@ export const configSchema = schema.object({ interval: schema.string({ validate: validateDurationSchema, defaultValue: '5m' }), removalDelay: schema.string({ validate: validateDurationSchema, defaultValue: '1h' }), }), - enableImportExport: schema.boolean({ defaultValue: false }), }); export type AlertsConfig = TypeOf; diff --git a/x-pack/plugins/alerting/server/health/get_state.test.ts b/x-pack/plugins/alerting/server/health/get_state.test.ts index 2dddf81e3b766..24f3c101b26b6 100644 --- a/x-pack/plugins/alerting/server/health/get_state.test.ts +++ b/x-pack/plugins/alerting/server/health/get_state.test.ts @@ -71,7 +71,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }), pollInterval ).subscribe(); @@ -105,7 +104,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }), pollInterval, retryDelay @@ -150,7 +148,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }) ).toPromise(); @@ -181,7 +178,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }) ).toPromise(); @@ -212,7 +208,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }) ).toPromise(); @@ -240,7 +235,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }), retryDelay ).subscribe((status) => { @@ -271,7 +265,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }), retryDelay ).subscribe((status) => { @@ -308,7 +301,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }) ).toPromise(); diff --git a/x-pack/plugins/alerting/server/lib/license_state.test.ts b/x-pack/plugins/alerting/server/lib/license_state.test.ts index a1c326656f735..e04ce85b35374 100644 --- a/x-pack/plugins/alerting/server/lib/license_state.test.ts +++ b/x-pack/plugins/alerting/server/lib/license_state.test.ts @@ -70,6 +70,7 @@ describe('getLicenseCheckForAlertType', () => { executor: jest.fn(), producer: 'alerts', minimumLicenseRequired: 'gold', + isExportable: true, recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, }; @@ -204,6 +205,7 @@ describe('ensureLicenseForAlertType()', () => { executor: jest.fn(), producer: 'alerts', minimumLicenseRequired: 'gold', + isExportable: true, recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, }; diff --git a/x-pack/plugins/alerting/server/plugin.test.ts b/x-pack/plugins/alerting/server/plugin.test.ts index 4e9249944a6bf..9adc3cc9d6569 100644 --- a/x-pack/plugins/alerting/server/plugin.test.ts +++ b/x-pack/plugins/alerting/server/plugin.test.ts @@ -18,7 +18,6 @@ import { AlertsConfig } from './config'; import { AlertType } from './types'; import { eventLogMock } from '../../event_log/server/mocks'; import { actionsMock } from '../../actions/server/mocks'; -import mappings from './saved_objects/mappings.json'; describe('Alerting Plugin', () => { describe('setup()', () => { @@ -37,7 +36,6 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }); plugin = new AlertingPlugin(context); @@ -61,78 +59,13 @@ describe('Alerting Plugin', () => { ); }); - it('should register saved object with no management capability if enableImportExport is false', async () => { - const context = coreMock.createPluginInitializerContext({ - healthCheck: { - interval: '5m', - }, - invalidateApiKeysTask: { - interval: '5m', - removalDelay: '1h', - }, - enableImportExport: false, - }); - plugin = new AlertingPlugin(context); - - const setupMocks = coreMock.createSetup(); - await plugin.setup(setupMocks, { - licensing: licensingMock.createSetup(), - encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), - taskManager: taskManagerMock.createSetup(), - eventLog: eventLogServiceMock.create(), - actions: actionsMock.createSetup(), - statusService: statusServiceMock.createSetupContract(), - }); - - expect(setupMocks.savedObjects.registerType).toHaveBeenCalledTimes(2); - const registerAlertingSavedObject = setupMocks.savedObjects.registerType.mock.calls[0][0]; - expect(registerAlertingSavedObject.name).toEqual('alert'); - expect(registerAlertingSavedObject.hidden).toBe(true); - expect(registerAlertingSavedObject.mappings).toEqual(mappings.alert); - expect(registerAlertingSavedObject.management).toBeUndefined(); - }); - - it('should register saved object with import/export capability if enableImportExport is true', async () => { - const context = coreMock.createPluginInitializerContext({ - healthCheck: { - interval: '5m', - }, - invalidateApiKeysTask: { - interval: '5m', - removalDelay: '1h', - }, - enableImportExport: true, - }); - plugin = new AlertingPlugin(context); - - const setupMocks = coreMock.createSetup(); - await plugin.setup(setupMocks, { - licensing: licensingMock.createSetup(), - encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), - taskManager: taskManagerMock.createSetup(), - eventLog: eventLogServiceMock.create(), - actions: actionsMock.createSetup(), - statusService: statusServiceMock.createSetupContract(), - }); - - expect(setupMocks.savedObjects.registerType).toHaveBeenCalledTimes(2); - const registerAlertingSavedObject = setupMocks.savedObjects.registerType.mock.calls[0][0]; - expect(registerAlertingSavedObject.name).toEqual('alert'); - expect(registerAlertingSavedObject.hidden).toBe(true); - expect(registerAlertingSavedObject.mappings).toEqual(mappings.alert); - expect(registerAlertingSavedObject.management).not.toBeUndefined(); - expect(registerAlertingSavedObject.management?.importableAndExportable).toBe(true); - expect(registerAlertingSavedObject.management?.getTitle).not.toBeUndefined(); - expect(registerAlertingSavedObject.management?.onImport).not.toBeUndefined(); - expect(registerAlertingSavedObject.management?.onExport).not.toBeUndefined(); - }); - describe('registerType()', () => { let setup: PluginSetupContract; const sampleAlertType: AlertType = { id: 'test', name: 'test', minimumLicenseRequired: 'basic', + isExportable: true, actionGroups: [], defaultActionGroupId: 'default', producer: 'test', @@ -189,7 +122,6 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }); const plugin = new AlertingPlugin(context); @@ -229,7 +161,6 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }); const plugin = new AlertingPlugin(context); @@ -283,7 +214,6 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }); const plugin = new AlertingPlugin(context); diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 5afa1b235a8c1..df63625bf242d 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -192,8 +192,6 @@ export class AlertingPlugin { event: { provider: EVENT_LOG_PROVIDER }, }); - setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects, this.config); - this.eventLogService = plugins.eventLog; plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); @@ -221,6 +219,13 @@ export class AlertingPlugin { }); } + setupSavedObjects( + core.savedObjects, + plugins.encryptedSavedObjects, + this.alertTypeRegistry, + this.logger + ); + initializeApiKeyInvalidator( this.logger, core.getStartServices(), diff --git a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts index 3e6f2f484a6d8..e2bf1afdb0f6e 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts @@ -47,6 +47,7 @@ describe('listAlertTypesRoute', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, authorizedConsumers: {}, actionVariables: { @@ -79,6 +80,7 @@ describe('listAlertTypesRoute', () => { "defaultActionGroupId": "default", "enabledInLicense": true, "id": "1", + "isExportable": true, "minimumLicenseRequired": "basic", "name": "name", "producer": "test", @@ -120,6 +122,7 @@ describe('listAlertTypesRoute', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, authorizedConsumers: {}, actionVariables: { @@ -172,6 +175,7 @@ describe('listAlertTypesRoute', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, authorizedConsumers: {}, actionVariables: { diff --git a/x-pack/plugins/alerting/server/routes/rule_types.test.ts b/x-pack/plugins/alerting/server/routes/rule_types.test.ts index 58c9a4b4c46fd..4f04f8c7575c5 100644 --- a/x-pack/plugins/alerting/server/routes/rule_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule_types.test.ts @@ -48,6 +48,7 @@ describe('ruleTypesRoute', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, authorizedConsumers: {}, actionVariables: { @@ -70,6 +71,7 @@ describe('ruleTypesRoute', () => { ], default_action_group_id: 'default', minimum_license_required: 'basic', + is_exportable: true, recovery_action_group: RecoveredActionGroup, authorized_consumers: {}, action_variables: { @@ -102,6 +104,7 @@ describe('ruleTypesRoute', () => { "default_action_group_id": "default", "enabled_in_license": true, "id": "1", + "is_exportable": true, "minimum_license_required": "basic", "name": "name", "producer": "test", @@ -143,6 +146,7 @@ describe('ruleTypesRoute', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, authorizedConsumers: {}, actionVariables: { @@ -195,6 +199,7 @@ describe('ruleTypesRoute', () => { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, authorizedConsumers: {}, actionVariables: { diff --git a/x-pack/plugins/alerting/server/routes/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule_types.ts index a3a44f9b013cd..f67e07f13feed 100644 --- a/x-pack/plugins/alerting/server/routes/rule_types.ts +++ b/x-pack/plugins/alerting/server/routes/rule_types.ts @@ -19,6 +19,7 @@ const rewriteBodyRes: RewriteResponseCase = (result actionGroups, defaultActionGroupId, minimumLicenseRequired, + isExportable, actionVariables, authorizedConsumers, ...rest @@ -29,6 +30,7 @@ const rewriteBodyRes: RewriteResponseCase = (result action_groups: actionGroups, default_action_group_id: defaultActionGroupId, minimum_license_required: minimumLicenseRequired, + is_exportable: isExportable, action_variables: actionVariables, authorized_consumers: authorizedConsumers, }) diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index 1ad0f972b2ec0..88ee3179ab3d8 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -6,6 +6,7 @@ */ import type { + Logger, SavedObject, SavedObjectsExportTransformContext, SavedObjectsServiceSetup, @@ -17,7 +18,9 @@ import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objec import { transformRulesForExport } from './transform_rule_for_export'; import { RawAlert } from '../types'; import { getImportWarnings } from './get_import_warnings'; -import { AlertsConfig } from '../config'; +import { isRuleExportable } from './is_rule_exportable'; +import { AlertTypeRegistry } from '../alert_type_registry'; + export { partiallyUpdateAlert } from './partially_update_alert'; export const AlertAttributesExcludedFromAAD = [ @@ -44,65 +47,63 @@ export type AlertAttributesExcludedFromAADType = export function setupSavedObjects( savedObjects: SavedObjectsServiceSetup, encryptedSavedObjects: EncryptedSavedObjectsPluginSetup, - alertingConfig: Promise + ruleTypeRegistry: AlertTypeRegistry, + logger: Logger ) { - alertingConfig.then((config: AlertsConfig) => { - savedObjects.registerType({ - name: 'alert', - hidden: true, - namespaceType: 'single', - migrations: getMigrations(encryptedSavedObjects), - mappings: mappings.alert as SavedObjectsTypeMappingDefinition, - ...(config.enableImportExport - ? { - management: { - importableAndExportable: true, - getTitle(ruleSavedObject: SavedObject) { - return `Rule: [${ruleSavedObject.attributes.name}]`; - }, - onImport(ruleSavedObjects) { - return { - warnings: getImportWarnings(ruleSavedObjects), - }; - }, - onExport( - context: SavedObjectsExportTransformContext, - objects: Array> - ) { - return transformRulesForExport(objects); - }, - }, - } - : {}), - }); + savedObjects.registerType({ + name: 'alert', + hidden: true, + namespaceType: 'single', + migrations: getMigrations(encryptedSavedObjects), + mappings: mappings.alert as SavedObjectsTypeMappingDefinition, + management: { + importableAndExportable: true, + getTitle(ruleSavedObject: SavedObject) { + return `Rule: [${ruleSavedObject.attributes.name}]`; + }, + onImport(ruleSavedObjects) { + return { + warnings: getImportWarnings(ruleSavedObjects), + }; + }, + onExport( + context: SavedObjectsExportTransformContext, + objects: Array> + ) { + return transformRulesForExport(objects); + }, + isExportable(ruleSavedObject: SavedObject) { + return isRuleExportable(ruleSavedObject, ruleTypeRegistry, logger); + }, + }, + }); - savedObjects.registerType({ - name: 'api_key_pending_invalidation', - hidden: true, - namespaceType: 'agnostic', - mappings: { - properties: { - apiKeyId: { - type: 'keyword', - }, - createdAt: { - type: 'date', - }, + savedObjects.registerType({ + name: 'api_key_pending_invalidation', + hidden: true, + namespaceType: 'agnostic', + mappings: { + properties: { + apiKeyId: { + type: 'keyword', + }, + createdAt: { + type: 'date', }, }, - }); + }, + }); - // Encrypted attributes - encryptedSavedObjects.registerType({ - type: 'alert', - attributesToEncrypt: new Set(['apiKey']), - attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD), - }); + // Encrypted attributes + encryptedSavedObjects.registerType({ + type: 'alert', + attributesToEncrypt: new Set(['apiKey']), + attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD), + }); - // Encrypted attributes - encryptedSavedObjects.registerType({ - type: 'api_key_pending_invalidation', - attributesToEncrypt: new Set(['apiKeyId']), - }); + // Encrypted attributes + encryptedSavedObjects.registerType({ + type: 'api_key_pending_invalidation', + attributesToEncrypt: new Set(['apiKeyId']), }); } diff --git a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts new file mode 100644 index 0000000000000..cc2dfbd3e2d2f --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts @@ -0,0 +1,208 @@ +/* + * 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 { MockedLogger, loggerMock } from '@kbn/logging/target/mocks'; +import { TaskRunnerFactory } from '../task_runner'; +import { AlertTypeRegistry, ConstructorOptions } from '../alert_type_registry'; +import { taskManagerMock } from '../../../task_manager/server/mocks'; +import { ILicenseState } from '../lib/license_state'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { licensingMock } from '../../../licensing/server/mocks'; +import { isRuleExportable } from './is_rule_exportable'; + +let ruleTypeRegistryParams: ConstructorOptions; +let logger: MockedLogger; +let mockedLicenseState: jest.Mocked; +const taskManager = taskManagerMock.createSetup(); + +beforeEach(() => { + jest.resetAllMocks(); + mockedLicenseState = licenseStateMock.create(); + logger = loggerMock.create(); + ruleTypeRegistryParams = { + taskManager, + taskRunnerFactory: new TaskRunnerFactory(), + licenseState: mockedLicenseState, + licensing: licensingMock.createSetup(), + }; +}); + +describe('isRuleExportable', () => { + it('should return true if rule type isExportable is true', () => { + const registry = new AlertTypeRegistry(ruleTypeRegistryParams); + registry.register({ + id: 'foo', + name: 'Foo', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + executor: jest.fn(), + producer: 'alerts', + }); + expect( + isRuleExportable( + { + id: '1', + type: 'alert', + attributes: { + enabled: true, + name: 'rule-name', + tags: ['tag-1', 'tag-2'], + alertTypeId: 'foo', + consumer: 'alert-consumer', + schedule: { interval: '1m' }, + actions: [], + params: {}, + createdBy: 'me', + updatedBy: 'me', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + apiKey: '4tndskbuhewotw4klrhgjewrt9u', + apiKeyOwner: 'me', + throttle: null, + notifyWhen: 'onActionGroupChange', + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'active', + lastExecutionDate: '2020-08-20T19:23:38Z', + error: null, + }, + scheduledTaskId: '2q5tjbf3q45twer', + }, + references: [], + }, + registry, + logger + ) + ).toEqual(true); + }); + + it('should return false and log warning if rule type isExportable is false', () => { + const registry = new AlertTypeRegistry(ruleTypeRegistryParams); + registry.register({ + id: 'foo', + name: 'Foo', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: false, + executor: jest.fn(), + producer: 'alerts', + }); + expect( + isRuleExportable( + { + id: '1', + type: 'alert', + attributes: { + enabled: true, + name: 'rule-name', + tags: ['tag-1', 'tag-2'], + alertTypeId: 'foo', + consumer: 'alert-consumer', + schedule: { interval: '1m' }, + actions: [], + params: {}, + createdBy: 'me', + updatedBy: 'me', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + apiKey: '4tndskbuhewotw4klrhgjewrt9u', + apiKeyOwner: 'me', + throttle: null, + notifyWhen: 'onActionGroupChange', + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'active', + lastExecutionDate: '2020-08-20T19:23:38Z', + error: null, + }, + scheduledTaskId: '2q5tjbf3q45twer', + }, + references: [], + }, + registry, + logger + ) + ).toEqual(false); + expect(logger.warn).toHaveBeenCalledWith( + `Skipping export of rule \"1\" because rule type \"foo\" is not exportable through this interface.` + ); + }); + + it('should return false and log warning if rule type is not registered', () => { + const registry = new AlertTypeRegistry(ruleTypeRegistryParams); + registry.register({ + id: 'foo', + name: 'Foo', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: false, + executor: jest.fn(), + producer: 'alerts', + }); + expect( + isRuleExportable( + { + id: '1', + type: 'alert', + attributes: { + enabled: true, + name: 'rule-name', + tags: ['tag-1', 'tag-2'], + alertTypeId: 'bar', + consumer: 'alert-consumer', + schedule: { interval: '1m' }, + actions: [], + params: {}, + createdBy: 'me', + updatedBy: 'me', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + apiKey: '4tndskbuhewotw4klrhgjewrt9u', + apiKeyOwner: 'me', + throttle: null, + notifyWhen: 'onActionGroupChange', + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'active', + lastExecutionDate: '2020-08-20T19:23:38Z', + error: null, + }, + scheduledTaskId: '2q5tjbf3q45twer', + }, + references: [], + }, + registry, + logger + ) + ).toEqual(false); + expect(logger.warn).toHaveBeenCalledWith( + `Skipping export of rule \"1\" because rule type \"bar\" is not recognized.` + ); + }); +}); diff --git a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.ts b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.ts new file mode 100644 index 0000000000000..38290e5f465cc --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.ts @@ -0,0 +1,33 @@ +/* + * 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 { Logger, SavedObject } from 'kibana/server'; +import { RawAlert } from '../types'; +import { AlertTypeRegistry } from '../alert_type_registry'; + +export function isRuleExportable( + rule: SavedObject, + ruleTypeRegistry: AlertTypeRegistry, + logger: Logger +): boolean { + const ruleSO = rule as SavedObject; + try { + const ruleType = ruleTypeRegistry.get(ruleSO.attributes.alertTypeId); + if (!ruleType.isExportable) { + logger.warn( + `Skipping export of rule "${ruleSO.id}" because rule type "${ruleSO.attributes.alertTypeId}" is not exportable through this interface.` + ); + } + + return ruleType.isExportable; + } catch (err) { + logger.warn( + `Skipping export of rule "${ruleSO.id}" because rule type "${ruleSO.attributes.alertTypeId}" is not recognized.` + ); + return false; + } +} diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts index 1dcd19119b6fd..b264428b4d6f2 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts @@ -44,6 +44,7 @@ const alertType: NormalizedAlertType< ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: { id: 'recovered', name: 'Recovered', diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index 88d1b1b24a4ec..4f650975f830e 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -44,6 +44,7 @@ const alertType: jest.Mocked = { actionGroups: [{ id: 'default', name: 'Default' }, RecoveredActionGroup], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: RecoveredActionGroup, executor: jest.fn(), producer: 'alerts', diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts index 343dffa0d5e70..050345f3e617f 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts @@ -26,6 +26,7 @@ const alertType: UntypedNormalizedAlertType = { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: { id: 'recovered', name: 'Recovered', diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index f8846035e6b02..f21e17adc841d 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -146,6 +146,7 @@ export interface AlertType< params?: ActionVariable[]; }; minimumLicenseRequired: LicenseType; + isExportable: boolean; } export type UntypedAlertType = AlertType< diff --git a/x-pack/plugins/apm/common/alert_types.ts b/x-pack/plugins/apm/common/alert_types.ts index 12df93d54b296..ad233c7f6df92 100644 --- a/x-pack/plugins/apm/common/alert_types.ts +++ b/x-pack/plugins/apm/common/alert_types.ts @@ -33,6 +33,7 @@ export const ALERT_TYPES_CONFIG: Record< actionGroups: Array>; defaultActionGroupId: ThresholdMetActionGroupId; minimumLicenseRequired: string; + isExportable: boolean; producer: string; } > = { @@ -44,6 +45,7 @@ export const ALERT_TYPES_CONFIG: Record< defaultActionGroupId: THRESHOLD_MET_GROUP_ID, minimumLicenseRequired: 'basic', producer: 'apm', + isExportable: true, }, [AlertType.TransactionDuration]: { name: i18n.translate('xpack.apm.transactionDurationAlert.name', { @@ -53,6 +55,7 @@ export const ALERT_TYPES_CONFIG: Record< defaultActionGroupId: THRESHOLD_MET_GROUP_ID, minimumLicenseRequired: 'basic', producer: 'apm', + isExportable: true, }, [AlertType.TransactionDurationAnomaly]: { name: i18n.translate('xpack.apm.transactionDurationAnomalyAlert.name', { @@ -62,6 +65,7 @@ export const ALERT_TYPES_CONFIG: Record< defaultActionGroupId: THRESHOLD_MET_GROUP_ID, minimumLicenseRequired: 'basic', producer: 'apm', + isExportable: true, }, [AlertType.TransactionErrorRate]: { name: i18n.translate('xpack.apm.transactionErrorRateAlert.name', { @@ -71,6 +75,7 @@ export const ALERT_TYPES_CONFIG: Record< defaultActionGroupId: THRESHOLD_MET_GROUP_ID, minimumLicenseRequired: 'basic', producer: 'apm', + isExportable: true, }, }; diff --git a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts index 2a63c53b626cd..7548d6eba060a 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts @@ -71,6 +71,7 @@ export function registerErrorCountAlertType({ }, producer: 'apm', minimumLicenseRequired: 'basic', + isExportable: true, executor: async ({ services, params }) => { const config = await config$.pipe(take(1)).toPromise(); const alertParams = params; diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts index 24a6376761a7d..ca7806251f75e 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts @@ -79,6 +79,7 @@ export function registerTransactionDurationAlertType({ }, producer: 'apm', minimumLicenseRequired: 'basic', + isExportable: true, executor: async ({ services, params }) => { const config = await config$.pipe(take(1)).toPromise(); const alertParams = params; diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts index f640925b0a0fa..de0657d075d7f 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts @@ -87,6 +87,7 @@ export function registerTransactionDurationAnomalyAlertType({ }, producer: 'apm', minimumLicenseRequired: 'basic', + isExportable: true, executor: async ({ services, params }) => { if (!ml) { return {}; diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts index 47ed5236ce74c..718ffd9c92167 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts @@ -77,6 +77,7 @@ export function registerTransactionErrorRateAlertType({ }, producer: 'apm', minimumLicenseRequired: 'basic', + isExportable: true, executor: async ({ services, params: alertParams }) => { const config = await config$.pipe(take(1)).toPromise(); const indices = await getApmIndices({ diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts index 81204c7b71a68..a2d8e522c7c8d 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts @@ -89,6 +89,7 @@ export const registerMetricInventoryThresholdAlertType = ( actionGroups: [FIRED_ACTIONS, WARNING_ACTIONS], producer: 'infrastructure', minimumLicenseRequired: 'basic', + isExportable: true, executor: createInventoryMetricThresholdExecutor(libs), actionVariables: { context: [ diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts index b7c6881b20390..62d92d0487ff7 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts @@ -107,6 +107,7 @@ export async function registerLogThresholdAlertType( defaultActionGroupId: FIRED_ACTIONS.id, actionGroups: [FIRED_ACTIONS], minimumLicenseRequired: 'basic', + isExportable: true, executor: createLogThresholdExecutor(libs), actionVariables: { context: [ diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_alert_type.ts index 2adf37c60cf3a..63354111a1a98 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_alert_type.ts @@ -64,6 +64,7 @@ export const registerMetricAnomalyAlertType = ( actionGroups: [FIRED_ACTIONS], producer: 'infrastructure', minimumLicenseRequired: 'basic', + isExportable: true, executor: createMetricAnomalyExecutor(libs, ml), actionVariables: { context: [ diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts index 7dbae03f20fbd..e519d67b446a5 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts @@ -100,6 +100,7 @@ export function registerMetricThresholdAlertType(libs: InfraBackendLibs): Metric defaultActionGroupId: FIRED_ACTIONS.id, actionGroups: [FIRED_ACTIONS, WARNING_ACTIONS], minimumLicenseRequired: 'basic', + isExportable: true, executor: createMetricThresholdExecutor(libs), actionVariables: { context: [ diff --git a/x-pack/plugins/ml/server/lib/alerts/register_anomaly_detection_alert_type.ts b/x-pack/plugins/ml/server/lib/alerts/register_anomaly_detection_alert_type.ts index f39b3850b71b1..93c627c0f6311 100644 --- a/x-pack/plugins/ml/server/lib/alerts/register_anomaly_detection_alert_type.ts +++ b/x-pack/plugins/ml/server/lib/alerts/register_anomaly_detection_alert_type.ts @@ -119,6 +119,7 @@ export function registerAnomalyDetectionAlertType({ }, producer: PLUGIN_ID, minimumLicenseRequired: MINIMUM_FULL_LICENSE, + isExportable: true, async executor({ services, params, alertId, state, previousStartedAt, startedAt }) { const fakeRequest = {} as KibanaRequest; const { execute } = mlSharedServices.alertingServiceProvider( diff --git a/x-pack/plugins/monitoring/server/alerts/base_alert.ts b/x-pack/plugins/monitoring/server/alerts/base_alert.ts index bb80d84210a48..8954a4ae2486d 100644 --- a/x-pack/plugins/monitoring/server/alerts/base_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/base_alert.ts @@ -96,6 +96,7 @@ export class BaseAlert { ], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: false, executor: ( options: AlertExecutorOptions & { state: ExecutedState; diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts index 85e69eb51fd02..a362dcccc2f0f 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts @@ -40,6 +40,7 @@ function createRule() { }, id: 'test_type', minimumLicenseRequired: 'basic', + isExportable: true, name: 'Test type', producer: 'test', actionVariables: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts index a4863e577c6bc..c85848ba6dcfe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts @@ -37,6 +37,7 @@ export const rulesNotificationAlertType = ({ }), }, minimumLicenseRequired: 'basic', + isExportable: false, async executor({ startedAt, previousStartedAt, alertId, services, params }) { const ruleAlertSavedObject = await services.savedObjectsClient.get( 'alert', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts index 39d02c808d09e..b98bd9b3551c3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts @@ -45,6 +45,7 @@ export const createEqlAlertType = (ruleDataClient: RuleDataClient, logger: Logge context: [{ name: 'server', description: 'the server' }], }, minimumLicenseRequired: 'basic', + isExportable: false, producer: 'security-solution', async executor({ startedAt, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts index c07d0436cc90d..14252bf62ef83 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts @@ -57,6 +57,7 @@ export const mlAlertType = createSecurityMlRuleType({ context: [{ name: 'server', description: 'the server' }], }, minimumLicenseRequired: 'basic', + isExportable: false, producer: 'security-solution', async executor({ services: { alertWithPersistence, findAlerts }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts index 39f325fd6cf8f..4ca9448f5e3c7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts @@ -43,6 +43,7 @@ export const createQueryAlertType = (ruleDataClient: RuleDataClient, logger: Log context: [{ name: 'server', description: 'the server' }], }, minimumLicenseRequired: 'basic', + isExportable: false, producer: 'security-solution', async executor({ services: { alertWithPersistence, findAlerts }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts index d4721e8bab11d..fa291ef3139cd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts @@ -113,6 +113,7 @@ export const createThresholdAlertType = (ruleDataClient: RuleDataClient, logger: context: [{ name: 'server', description: 'the server' }], }, minimumLicenseRequired: 'basic', + isExportable: false, producer: 'security-solution', async executor({ startedAt, services, params, alertId }) { const fromDate = moment(startedAt).subtract(moment.duration(5, 'm')); // hardcoded 5-minute rule interval diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 32bd6d71bfb1d..ba665fa43e8b8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -103,6 +103,7 @@ export const signalRulesAlertType = ({ }, producer: SERVER_APP_ID, minimumLicenseRequired: 'basic', + isExportable: false, async executor({ previousStartedAt, startedAt, diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts index b81bc19d5c731..c9f233002d79b 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts @@ -140,6 +140,7 @@ export function getAlertType( ], }, minimumLicenseRequired: 'basic', + isExportable: true, executor, producer: STACK_ALERTS_FEATURE_ID, }; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts index e3d379f2869b9..43ae726fa2478 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts @@ -177,5 +177,6 @@ export function getAlertType(logger: Logger): GeoContainmentAlertType { }, actionVariables, minimumLicenseRequired: 'gold', + isExportable: true, }; } diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts index a242c1e0eb29e..aa56951b5dcba 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts @@ -125,6 +125,7 @@ export function getAlertType( ], }, minimumLicenseRequired: 'basic', + isExportable: true, executor, producer: STACK_ALERTS_FEATURE_ID, }; diff --git a/x-pack/plugins/uptime/server/lib/alerts/duration_anomaly.ts b/x-pack/plugins/uptime/server/lib/alerts/duration_anomaly.ts index b3262976b0cac..981a7e7ca3920 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/duration_anomaly.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/duration_anomaly.ts @@ -89,6 +89,7 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory state: [...durationAnomalyTranslations.actionVariables, ...commonStateTranslations], }, minimumLicenseRequired: 'basic', + isExportable: true, async executor({ options, uptimeEsClient, savedObjectsClient, dynamicSettings }) { const { services: { alertInstanceFactory }, diff --git a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts index c5a6ef877c47a..6f3e3303f6bdc 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts @@ -258,6 +258,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory = ( state: [...commonMonitorStateI18, ...commonStateTranslations], }, minimumLicenseRequired: 'basic', + isExportable: true, async executor({ options: { params: rawParams, diff --git a/x-pack/plugins/uptime/server/lib/alerts/tls.ts b/x-pack/plugins/uptime/server/lib/alerts/tls.ts index f29744fdbb70f..09f5e2fe0f6d5 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/tls.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/tls.ts @@ -112,6 +112,7 @@ export const tlsAlertFactory: UptimeAlertTypeFactory = (_server, state: [...tlsTranslations.actionVariables, ...commonStateTranslations], }, minimumLicenseRequired: 'basic', + isExportable: true, async executor({ options, dynamicSettings, uptimeEsClient }) { const { services: { alertInstanceFactory }, diff --git a/x-pack/plugins/uptime/server/lib/alerts/tls_legacy.ts b/x-pack/plugins/uptime/server/lib/alerts/tls_legacy.ts index 8f1c0093e60ac..5bf91b7c5486d 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/tls_legacy.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/tls_legacy.ts @@ -103,6 +103,7 @@ export const tlsLegacyAlertFactory: UptimeAlertTypeFactory = (_s state: [...tlsTranslations.actionVariables, ...commonStateTranslations], }, minimumLicenseRequired: 'basic', + isExportable: true, async executor({ options, dynamicSettings, uptimeEsClient }) { const { services: { alertInstanceFactory }, diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts index 3e622b49d03df..3c9d783f5a357 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts @@ -81,6 +81,7 @@ function getAlwaysFiringAlertType() { producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, actionVariables: { state: [{ name: 'instanceStateValue', description: 'the instance state value' }], params: [{ name: 'instanceParamsValue', description: 'the instance params value' }], @@ -167,6 +168,7 @@ function getCumulativeFiringAlertType() { producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor(alertExecutorOptions) { const { services, state } = alertExecutorOptions; const group = 'default'; @@ -212,6 +214,7 @@ function getNeverFiringAlertType() { producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor({ services, params, state }) { await services.scopedClusterClient.asCurrentUser.index({ index: params.index, @@ -252,6 +255,7 @@ function getFailingAlertType() { producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor({ services, params, state }) { await services.scopedClusterClient.asCurrentUser.index({ index: params.index, @@ -290,6 +294,7 @@ function getAuthorizationAlertType(core: CoreSetup) { defaultActionGroupId: 'default', producer: 'alertsFixture', minimumLicenseRequired: 'basic', + isExportable: true, validate: { params: paramsSchema, }, @@ -376,6 +381,7 @@ function getValidationAlertType() { ], producer: 'alertsFixture', minimumLicenseRequired: 'basic', + isExportable: true, defaultActionGroupId: 'default', validate: { params: paramsSchema, @@ -404,6 +410,7 @@ function getPatternFiringAlertType() { producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor(alertExecutorOptions) { const { services, state, params } = alertExecutorOptions; const pattern = params.pattern; @@ -468,6 +475,7 @@ export function defineAlertTypes( producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor() {}, }; const goldNoopAlertType: AlertType<{}, {}, {}, {}, 'default'> = { @@ -477,6 +485,7 @@ export function defineAlertTypes( producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'gold', + isExportable: true, async executor() {}, }; const onlyContextVariablesAlertType: AlertType<{}, {}, {}, {}, 'default'> = { @@ -486,6 +495,7 @@ export function defineAlertTypes( producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, actionVariables: { context: [{ name: 'aContextVariable', description: 'this is a context variable' }], }, @@ -501,6 +511,7 @@ export function defineAlertTypes( state: [{ name: 'aStateVariable', description: 'this is a state variable' }], }, minimumLicenseRequired: 'basic', + isExportable: true, async executor() {}, }; const throwAlertType: AlertType<{}, {}, {}, {}, 'default'> = { @@ -515,6 +526,7 @@ export function defineAlertTypes( producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor() { throw new Error('this alert is intended to fail'); }, @@ -531,6 +543,7 @@ export function defineAlertTypes( producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor() { await new Promise((resolve) => setTimeout(resolve, 5000)); }, diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts_restricted/server/alert_types.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts_restricted/server/alert_types.ts index 884af7801855f..2255d1fa95e2d 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts_restricted/server/alert_types.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts_restricted/server/alert_types.ts @@ -20,6 +20,7 @@ export function defineAlertTypes( producer: 'alertsRestrictedFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, recoveryActionGroup: { id: 'restrictedRecovered', name: 'Restricted Recovery' }, async executor() {}, }; @@ -30,6 +31,7 @@ export function defineAlertTypes( producer: 'alertsRestrictedFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor() {}, }; alerting.registerType(noopRestrictedAlertType); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts index c851aaf2bbc88..f52f0977a630b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts @@ -30,6 +30,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { }, producer: 'alertsFixture', minimum_license_required: 'basic', + is_exportable: true, recovery_action_group: { id: 'recovered', name: 'Recovered', @@ -56,6 +57,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { }, producer: 'alertsRestrictedFixture', minimum_license_required: 'basic', + is_exportable: true, enabled_in_license: true, }; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts index 3d3cec4c30252..86a0e269b26d6 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts @@ -42,6 +42,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { }, producer: 'alertsFixture', minimum_license_required: 'basic', + is_exportable: true, enabled_in_license: true, }); expect(Object.keys(authorizedConsumers)).to.contain('alertsFixture'); @@ -126,6 +127,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { }, producer: 'alertsFixture', minimumLicenseRequired: 'basic', + isExportable: true, enabledInLicense: true, }); expect(Object.keys(authorizedConsumers)).to.contain('alertsFixture'); diff --git a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/server/plugin.ts b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/server/plugin.ts index 10a81e4309088..8d0d2c4f0be33 100644 --- a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/server/plugin.ts +++ b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/server/plugin.ts @@ -24,6 +24,7 @@ export const noopAlertType: AlertType<{}, {}, {}, {}, 'default'> = { actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', + isExportable: true, async executor() {}, producer: 'alerts', }; @@ -47,6 +48,7 @@ export const alwaysFiringAlertType: AlertType< defaultActionGroupId: 'default', producer: 'alerts', minimumLicenseRequired: 'basic', + isExportable: true, async executor(alertExecutorOptions) { const { services, state, params } = alertExecutorOptions; @@ -76,6 +78,7 @@ export const failingAlertType: AlertType