From 3b7c89fbe90bd894e5c2ad647233d5a1a198f0c9 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Thu, 23 May 2024 18:24:53 +0300 Subject: [PATCH] Change new schema --- .../alerting_example/server/plugin.ts | 45 +++++++----- .../features/src/security/kibana_features.ts | 19 ++--- .../authorization/alerting_authorization.ts | 11 ++- .../common/feature_kibana_privileges.ts | 8 +- .../plugins/features/common/kibana_feature.ts | 2 +- .../feature_privilege_iterator.ts | 73 +++++++++---------- .../plugins/features/server/feature_schema.ts | 49 +++++++------ .../plugins/ml/common/types/capabilities.ts | 13 +++- x-pack/plugins/ml/server/plugin.ts | 5 +- x-pack/plugins/monitoring/server/plugin.ts | 11 ++- .../apm/server/feature.ts | 15 ++-- .../infra/server/features.ts | 30 +++++--- .../observability/server/plugin.ts | 15 ++-- .../slo/server/plugin.ts | 15 ++-- .../synthetics/server/feature.ts | 15 ++-- .../alerting.test.ts | 56 +++++++------- .../feature_privilege_builder/alerting.ts | 17 ++--- x-pack/plugins/stack_alerts/server/feature.ts | 32 +++----- 18 files changed, 235 insertions(+), 196 deletions(-) diff --git a/x-pack/examples/alerting_example/server/plugin.ts b/x-pack/examples/alerting_example/server/plugin.ts index be3d9b50f1722..f02580e78f702 100644 --- a/x-pack/examples/alerting_example/server/plugin.ts +++ b/x-pack/examples/alerting_example/server/plugin.ts @@ -75,24 +75,27 @@ export class AlertingExamplePlugin implements Plugin ({ + ruleTypeId, + consumers: [SERVER_APP_ID], +})); + export const getSecurityBaseKibanaFeature = ({ savedObjects, }: SecurityFeatureParams): BaseKibanaFeatureConfig => ({ @@ -57,7 +62,7 @@ export const getSecurityBaseKibanaFeature = ({ management: { insightsAndAlerting: ['triggersActions'], }, - alerting: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] }, + alerting: alertingFeatures, privileges: { all: { app: [APP_ID, CLOUD_POSTURE_APP_ID, CLOUD_DEFEND_APP_ID, 'kibana'], @@ -78,12 +83,8 @@ export const getSecurityBaseKibanaFeature = ({ read: [], }, alerting: { - rule: { - all: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] }, - }, - alert: { - all: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] }, - }, + rule: { all: alertingFeatures }, + alert: { all: alertingFeatures }, }, management: { insightsAndAlerting: ['triggersActions'], @@ -100,10 +101,10 @@ export const getSecurityBaseKibanaFeature = ({ }, alerting: { rule: { - read: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] }, + read: alertingFeatures, }, alert: { - all: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] }, + all: alertingFeatures, }, }, management: { diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts index b67b986ef7d72..b3761fc63b445 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts @@ -115,14 +115,17 @@ export class AlertingAuthorization { // ignore features which are disabled in the user's space !disabledFeatures.has(id) && // ignore features which don't grant privileges to alerting - ((alerting?.ruleTypeIds?.length ?? 0 > 0) || (alerting?.consumers?.length ?? 0 > 0)) + (alerting?.length ?? 0 > 0) ) ); this.allPossibleConsumers = alertingFeaturesPromise.then((alertingFeatures) => { - const consumers = alertingFeatures - .flatMap((alertingFeature) => alertingFeature.alerting?.consumers) - .filter(Boolean) as string[]; + const consumers = alertingFeatures.flatMap( + (alertingFeature) => + alertingFeature.alerting + ?.flatMap((feature) => feature.consumers ?? []) + .filter(Boolean) as string[] + ); return consumers.length ? asAuthorizedConsumers([ALERTING_FEATURE_ID, ...consumers], { diff --git a/x-pack/plugins/features/common/feature_kibana_privileges.ts b/x-pack/plugins/features/common/feature_kibana_privileges.ts index 74811f56e8582..5083ae7450d74 100644 --- a/x-pack/plugins/features/common/feature_kibana_privileges.ts +++ b/x-pack/plugins/features/common/feature_kibana_privileges.ts @@ -103,7 +103,7 @@ export interface FeatureKibanaPrivileges { * } * ``` */ - all?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] }; + all?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>; /** * List of rule types which users should have read-only access to when granted this privilege. * @example @@ -113,7 +113,7 @@ export interface FeatureKibanaPrivileges { * } * ``` */ - read?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] }; + read?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>; }; alert?: { /** @@ -125,7 +125,7 @@ export interface FeatureKibanaPrivileges { * } * ``` */ - all?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] }; + all?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>; /** * List of rule types for which users should have read-only access to their alert data when granted this privilege. * @example @@ -135,7 +135,7 @@ export interface FeatureKibanaPrivileges { * } * ``` */ - read?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] }; + read?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>; }; }; diff --git a/x-pack/plugins/features/common/kibana_feature.ts b/x-pack/plugins/features/common/kibana_feature.ts index 34d45122dafac..3d30e7fd06022 100644 --- a/x-pack/plugins/features/common/kibana_feature.ts +++ b/x-pack/plugins/features/common/kibana_feature.ts @@ -101,7 +101,7 @@ export interface KibanaFeatureConfig { * Include both Alert Types registered by the feature and external Alert Types such as built-in * Alert Types and Alert Types provided by other features to which you wish to grant access. */ - alerting?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] }; + alerting?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>; /** * If your feature grants access to specific case types, you can specify them here to control visibility based on the current space. diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts index 6f803abd9de37..19a4cfacb9a81 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts @@ -108,50 +108,43 @@ function mergeWithSubFeatures( subFeaturePrivilege.savedObject.read ); + const mergeAlertingEntries = ( + entries: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }> + ): ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }> => { + const alertingMap = new Map>(); + + for (const entry of entries) { + const consumers = alertingMap.get(entry.ruleTypeId) ?? new Set(); + entry.consumers.forEach((consumer) => consumers.add(consumer)); + alertingMap.set(entry.ruleTypeId, consumers); + } + + return Array.from(alertingMap).map(([ruleTypeId, consumers]) => ({ + ruleTypeId, + consumers: Array.from(consumers), + })); + }; + mergedConfig.alerting = { rule: { - all: { - ruleTypeIds: mergeArrays( - mergedConfig.alerting?.rule?.all?.ruleTypeIds ?? [], - subFeaturePrivilege.alerting?.rule?.all?.ruleTypeIds ?? [] - ), - consumers: mergeArrays( - mergedConfig.alerting?.rule?.all?.consumers ?? [], - subFeaturePrivilege.alerting?.rule?.all?.consumers ?? [] - ), - }, - read: { - ruleTypeIds: mergeArrays( - mergedConfig.alerting?.rule?.read?.ruleTypeIds ?? [], - subFeaturePrivilege.alerting?.rule?.read?.ruleTypeIds ?? [] - ), - consumers: mergeArrays( - mergedConfig.alerting?.rule?.read?.consumers ?? [], - subFeaturePrivilege.alerting?.rule?.read?.consumers ?? [] - ), - }, + all: mergeAlertingEntries([ + ...(mergedConfig.alerting?.rule?.all ?? []), + ...(subFeaturePrivilege.alerting?.rule?.all ?? []), + ]), + read: mergeAlertingEntries([ + ...(mergedConfig.alerting?.rule?.read ?? []), + ...(subFeaturePrivilege.alerting?.rule?.read ?? []), + ]), }, alert: { - all: { - ruleTypeIds: mergeArrays( - mergedConfig.alerting?.alert?.all?.ruleTypeIds ?? [], - subFeaturePrivilege.alerting?.alert?.all?.ruleTypeIds ?? [] - ), - consumers: mergeArrays( - mergedConfig.alerting?.alert?.all?.consumers ?? [], - subFeaturePrivilege.alerting?.alert?.all?.consumers ?? [] - ), - }, - read: { - ruleTypeIds: mergeArrays( - mergedConfig.alerting?.alert?.read?.ruleTypeIds ?? [], - subFeaturePrivilege.alerting?.alert?.read?.ruleTypeIds ?? [] - ), - consumers: mergeArrays( - mergedConfig.alerting?.alert?.read?.consumers ?? [], - subFeaturePrivilege.alerting?.alert?.read?.consumers ?? [] - ), - }, + all: mergeAlertingEntries([ + ...(mergedConfig.alerting?.alert?.all ?? []), + ...(subFeaturePrivilege.alerting?.alert?.all ?? []), + ]), + read: mergeAlertingEntries([ + ...(mergedConfig.alerting?.alert?.read ?? []), + ...(subFeaturePrivilege.alerting?.alert?.read ?? []), + ]), }, }; diff --git a/x-pack/plugins/features/server/feature_schema.ts b/x-pack/plugins/features/server/feature_schema.ts index fb26984d439c1..388f609965596 100644 --- a/x-pack/plugins/features/server/feature_schema.ts +++ b/x-pack/plugins/features/server/feature_schema.ts @@ -63,10 +63,13 @@ const managementSchema = schema.recordOf( listOfCapabilitiesSchema ); const catalogueSchema = listOfCapabilitiesSchema; -const alertingSchema = schema.object({ - ruleTypeIds: schema.maybe(schema.arrayOf(schema.string())), - consumers: schema.maybe(schema.arrayOf(schema.string())), -}); +const alertingSchema = schema.arrayOf( + schema.object({ + ruleTypeId: schema.string(), + consumers: schema.arrayOf(schema.string()), + }) +); + const casesSchema = schema.arrayOf(schema.string()); const appCategorySchema = schema.object({ @@ -277,13 +280,7 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { kibanaFeatureSchema.validate(feature); // the following validation can't be enforced by the Joi schema, since it'd require us looking "up" the object graph for the list of valid value, which they explicitly forbid. - const { - app = [], - management = {}, - catalogue = [], - alerting: { ruleTypeIds = [], consumers = [] } = {}, - cases = [], - } = feature; + const { app = [], management = {}, catalogue = [], alerting = [], cases = [] } = feature; const unseenApps = new Set(app); @@ -296,7 +293,9 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { const unseenCatalogue = new Set(catalogue); - const unseenAlertTypes = new Set([...ruleTypeIds, ...consumers]); + const unseenAlertTypes = new Set( + alerting.flatMap(({ ruleTypeId, consumers }) => [ruleTypeId, ...consumers]) + ); const unseenCasesTypes = new Set(cases); @@ -327,23 +326,31 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { } function validateAlertingEntry(privilegeId: string, entry: FeatureKibanaPrivileges['alerting']) { + const getRuleTypeIdAndConsumers = ({ + ruleTypeId, + consumers, + }: { + ruleTypeId: string; + consumers: readonly string[]; + }) => [ruleTypeId, ...consumers]; + const all: string[] = [ - ...(entry?.rule?.all?.consumers ?? []), - ...(entry?.rule?.all?.ruleTypeIds ?? []), - ...(entry?.alert?.all?.consumers ?? []), - ...(entry?.alert?.all?.ruleTypeIds ?? []), + ...(entry?.rule?.all?.flatMap(getRuleTypeIdAndConsumers) ?? []), + ...(entry?.alert?.all?.flatMap(getRuleTypeIdAndConsumers) ?? []), ]; const read: string[] = [ - ...(entry?.rule?.read?.consumers ?? []), - ...(entry?.rule?.read?.ruleTypeIds ?? []), - ...(entry?.alert?.read?.consumers ?? []), - ...(entry?.alert?.read?.ruleTypeIds ?? []), + ...(entry?.rule?.read?.flatMap(getRuleTypeIdAndConsumers) ?? []), + ...(entry?.alert?.read?.flatMap(getRuleTypeIdAndConsumers) ?? []), ]; all.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes)); read.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes)); - const unknownAlertingEntries = difference([...all, ...read], [...ruleTypeIds, ...consumers]); + const unknownAlertingEntries = difference( + [...all, ...read], + alerting.flatMap(({ ruleTypeId, consumers }) => [ruleTypeId, ...consumers]) + ); + if (unknownAlertingEntries.length > 0) { throw new Error( `Feature privilege ${ diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index c2c25515b105f..ff97c4f7159d9 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -108,6 +108,11 @@ export function getDefaultCapabilities(): MlCapabilities { }; } +const alertingFeatures = Object.values(ML_ALERT_TYPES).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN_ID], +})); + export function getPluginPrivileges() { const apmUserMlCapabilitiesKeys = Object.keys(apmUserMlCapabilities); const userMlCapabilitiesKeys = Object.keys(userMlCapabilities); @@ -149,10 +154,10 @@ export function getPluginPrivileges() { }, alerting: { rule: { - all: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] }, + all: alertingFeatures, }, alert: { - all: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] }, + all: alertingFeatures, }, }, }, @@ -171,10 +176,10 @@ export function getPluginPrivileges() { }, alerting: { rule: { - read: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] }, + read: alertingFeatures, }, alert: { - read: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] }, + read: alertingFeatures, }, }, }, diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index c035ae14d2a02..487faffa84515 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -139,7 +139,10 @@ export class MlServerPlugin management: { insightsAndAlerting: ['jobsListLink', 'triggersActions'], }, - alerting: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] }, + alerting: Object.values(ML_ALERT_TYPES).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN_ID], + })), privileges: { all: admin, read: user, diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index a86361467dcd6..1e98695be420d 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -266,6 +266,11 @@ export class MonitoringPlugin } registerPluginInUI(plugins: PluginsSetup) { + const alertingFeatures = RULES.map((ruleTypeId) => ({ + ruleTypeId, + consumers: ['monitoring'], + })); + plugins.features.registerKibanaFeature({ id: 'monitoring', name: i18n.translate('xpack.monitoring.featureRegistry.monitoringFeatureName', { @@ -275,7 +280,7 @@ export class MonitoringPlugin app: ['monitoring', 'kibana'], catalogue: ['monitoring'], privileges: null, - alerting: { ruleTypeIds: RULES, consumers: ['monitoring'] }, + alerting: alertingFeatures, reserved: { description: i18n.translate('xpack.monitoring.feature.reserved.description', { defaultMessage: 'To grant users access, you should also assign the monitoring_user role.', @@ -292,10 +297,10 @@ export class MonitoringPlugin }, alerting: { rule: { - all: { ruleTypeIds: RULES, consumers: ['monitoring'] }, + all: alertingFeatures, }, alert: { - all: { ruleTypeIds: RULES, consumers: ['monitoring'] }, + all: alertingFeatures, }, }, ui: [], diff --git a/x-pack/plugins/observability_solution/apm/server/feature.ts b/x-pack/plugins/observability_solution/apm/server/feature.ts index f186ef1e2c03f..57e9b7fc2a3b5 100644 --- a/x-pack/plugins/observability_solution/apm/server/feature.ts +++ b/x-pack/plugins/observability_solution/apm/server/feature.ts @@ -17,7 +17,10 @@ import { APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE } from '@kbn/apm-data-access-plugi import { ApmRuleType } from '@kbn/rule-data-utils'; import { APM_SERVER_FEATURE_ID } from '../common/rules/apm_rule_types'; -const ruleTypes = Object.values(ApmRuleType); +const alertingFeatures = Object.values(ApmRuleType).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [APM_SERVER_FEATURE_ID], +})); export const APM_FEATURE = { id: APM_SERVER_FEATURE_ID, @@ -31,7 +34,7 @@ export const APM_FEATURE = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: { ruleTypeIds: ruleTypes, consumers: [APM_SERVER_FEATURE_ID] }, + alerting: alertingFeatures, // see x-pack/plugins/features/common/feature_kibana_privileges.ts privileges: { all: { @@ -44,10 +47,10 @@ export const APM_FEATURE = { }, alerting: { alert: { - all: { ruleTypeIds: ruleTypes, consumers: [APM_SERVER_FEATURE_ID] }, + all: alertingFeatures, }, rule: { - all: { ruleTypeIds: ruleTypes, consumers: [APM_SERVER_FEATURE_ID] }, + all: alertingFeatures, }, }, management: { @@ -65,10 +68,10 @@ export const APM_FEATURE = { }, alerting: { alert: { - read: { ruleTypeIds: ruleTypes, consumers: [APM_SERVER_FEATURE_ID] }, + read: alertingFeatures, }, rule: { - read: { ruleTypeIds: ruleTypes, consumers: [APM_SERVER_FEATURE_ID] }, + read: alertingFeatures, }, }, management: { diff --git a/x-pack/plugins/observability_solution/infra/server/features.ts b/x-pack/plugins/observability_solution/infra/server/features.ts index ff3b1eceaf4c8..ed47de593654e 100644 --- a/x-pack/plugins/observability_solution/infra/server/features.ts +++ b/x-pack/plugins/observability_solution/infra/server/features.ts @@ -30,6 +30,11 @@ const metricRuleTypes = [ ML_ANOMALY_DETECTION_RULE_TYPE_ID, ]; +const metricAlertingFeatures = metricRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [METRICS_FEATURE_ID], +})); + export const METRICS_FEATURE = { id: METRICS_FEATURE_ID, name: i18n.translate('xpack.infra.featureRegistry.linkInfrastructureTitle', { @@ -42,7 +47,7 @@ export const METRICS_FEATURE = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: { ruleTypeIds: metricRuleTypes, consumers: [METRICS_FEATURE_ID] }, + alerting: metricAlertingFeatures, privileges: { all: { app: ['infra', 'metrics', 'kibana'], @@ -54,10 +59,10 @@ export const METRICS_FEATURE = { }, alerting: { rule: { - all: { ruleTypeIds: metricRuleTypes, consumers: [METRICS_FEATURE_ID] }, + all: metricAlertingFeatures, }, alert: { - all: { ruleTypeIds: metricRuleTypes, consumers: [METRICS_FEATURE_ID] }, + all: metricAlertingFeatures, }, }, management: { @@ -75,10 +80,10 @@ export const METRICS_FEATURE = { }, alerting: { rule: { - read: { ruleTypeIds: metricRuleTypes, consumers: [METRICS_FEATURE_ID] }, + read: metricAlertingFeatures, }, alert: { - read: { ruleTypeIds: metricRuleTypes, consumers: [METRICS_FEATURE_ID] }, + read: metricAlertingFeatures, }, }, management: { @@ -96,6 +101,11 @@ const logsRuleTypes = [ ML_ANOMALY_DETECTION_RULE_TYPE_ID, ]; +const logsAlertingFeatures = logsRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [LOGS_FEATURE_ID], +})); + export const LOGS_FEATURE = { id: LOGS_FEATURE_ID, name: i18n.translate('xpack.infra.featureRegistry.linkLogsTitle', { @@ -108,7 +118,7 @@ export const LOGS_FEATURE = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: { ruleTypeIds: logsRuleTypes, consumers: [LOGS_FEATURE_ID] }, + alerting: logsAlertingFeatures, privileges: { all: { app: ['infra', 'logs', 'kibana'], @@ -120,10 +130,10 @@ export const LOGS_FEATURE = { }, alerting: { rule: { - all: { ruleTypeIds: logsRuleTypes, consumers: [LOGS_FEATURE_ID] }, + all: logsAlertingFeatures, }, alert: { - all: { ruleTypeIds: logsRuleTypes, consumers: [LOGS_FEATURE_ID] }, + all: logsAlertingFeatures, }, }, management: { @@ -137,10 +147,10 @@ export const LOGS_FEATURE = { api: ['infra', 'rac'], alerting: { rule: { - read: { ruleTypeIds: logsRuleTypes, consumers: [LOGS_FEATURE_ID] }, + read: logsAlertingFeatures, }, alert: { - read: { ruleTypeIds: logsRuleTypes, consumers: [LOGS_FEATURE_ID] }, + read: logsAlertingFeatures, }, }, management: { diff --git a/x-pack/plugins/observability_solution/observability/server/plugin.ts b/x-pack/plugins/observability_solution/observability/server/plugin.ts index 73090620c18e1..f796c99b8140b 100644 --- a/x-pack/plugins/observability_solution/observability/server/plugin.ts +++ b/x-pack/plugins/observability_solution/observability/server/plugin.ts @@ -82,6 +82,11 @@ const o11yRuleTypes = [ ...Object.values(ApmRuleType), ]; +const alertingFeatures = o11yRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [observabilityFeatureId], +})); + export class ObservabilityPlugin implements Plugin { private logger: Logger; @@ -234,7 +239,7 @@ export class ObservabilityPlugin implements Plugin { category: DEFAULT_APP_CATEGORIES.observability, app: [observabilityFeatureId], catalogue: [observabilityFeatureId], - alerting: { ruleTypeIds: o11yRuleTypes, consumers: [observabilityFeatureId] }, + alerting: alertingFeatures, privileges: { all: { app: [observabilityFeatureId], @@ -246,10 +251,10 @@ export class ObservabilityPlugin implements Plugin { }, alerting: { rule: { - all: { ruleTypeIds: o11yRuleTypes, consumers: [observabilityFeatureId] }, + all: alertingFeatures, }, alert: { - all: { ruleTypeIds: o11yRuleTypes, consumers: [observabilityFeatureId] }, + all: alertingFeatures, }, }, ui: ['read', 'write'], @@ -264,10 +269,10 @@ export class ObservabilityPlugin implements Plugin { }, alerting: { rule: { - read: { ruleTypeIds: o11yRuleTypes, consumers: [observabilityFeatureId] }, + read: alertingFeatures, }, alert: { - read: { ruleTypeIds: o11yRuleTypes, consumers: [observabilityFeatureId] }, + read: alertingFeatures, }, }, ui: ['read'], diff --git a/x-pack/plugins/observability_solution/slo/server/plugin.ts b/x-pack/plugins/observability_solution/slo/server/plugin.ts index a32f60b42d665..83483302c5873 100644 --- a/x-pack/plugins/observability_solution/slo/server/plugin.ts +++ b/x-pack/plugins/observability_solution/slo/server/plugin.ts @@ -79,6 +79,11 @@ export class SloPlugin implements Plugin { const savedObjectTypes = [SO_SLO_TYPE, SO_SLO_SETTINGS_TYPE]; + const alertingFeatures = sloRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [sloFeatureId], + })); + plugins.features.registerKibanaFeature({ id: sloFeatureId, name: i18n.translate('xpack.slo.featureRegistry.linkSloTitle', { @@ -88,7 +93,7 @@ export class SloPlugin implements Plugin { category: DEFAULT_APP_CATEGORIES.observability, app: [sloFeatureId, 'kibana'], catalogue: [sloFeatureId, 'observability'], - alerting: { ruleTypeIds: sloRuleTypes, consumers: [sloFeatureId] }, + alerting: alertingFeatures, privileges: { all: { app: [sloFeatureId, 'kibana'], @@ -100,10 +105,10 @@ export class SloPlugin implements Plugin { }, alerting: { rule: { - all: { ruleTypeIds: sloRuleTypes, consumers: [sloFeatureId] }, + all: alertingFeatures, }, alert: { - all: { ruleTypeIds: sloRuleTypes, consumers: [sloFeatureId] }, + all: alertingFeatures, }, }, ui: ['read', 'write'], @@ -118,10 +123,10 @@ export class SloPlugin implements Plugin { }, alerting: { rule: { - read: { ruleTypeIds: sloRuleTypes, consumers: [sloFeatureId] }, + read: alertingFeatures, }, alert: { - read: { ruleTypeIds: sloRuleTypes, consumers: [sloFeatureId] }, + read: alertingFeatures, }, }, ui: ['read'], diff --git a/x-pack/plugins/observability_solution/synthetics/server/feature.ts b/x-pack/plugins/observability_solution/synthetics/server/feature.ts index 7d69cd4283947..2893a39e9c128 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/feature.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/feature.ts @@ -27,6 +27,11 @@ const UPTIME_RULE_TYPES = [ const ruleTypes = [...UPTIME_RULE_TYPES, ...SYNTHETICS_RULE_TYPES]; +const alertingFeatures = ruleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN.ID], +})); + const elasticManagedLocationsEnabledPrivilege: SubFeaturePrivilegeGroupConfig = { groupType: 'independent' as SubFeaturePrivilegeGroupType, privileges: [ @@ -55,7 +60,7 @@ export const uptimeFeature = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: { ruleTypeIds: ruleTypes, consumers: [PLUGIN.ID] }, + alerting: alertingFeatures, privileges: { all: { app: ['uptime', 'kibana', 'synthetics'], @@ -73,10 +78,10 @@ export const uptimeFeature = { }, alerting: { rule: { - all: { ruleTypeIds: ruleTypes, consumers: [PLUGIN.ID] }, + all: alertingFeatures, }, alert: { - all: { ruleTypeIds: ruleTypes, consumers: [PLUGIN.ID] }, + all: alertingFeatures, }, }, management: { @@ -100,10 +105,10 @@ export const uptimeFeature = { }, alerting: { rule: { - read: { ruleTypeIds: ruleTypes, consumers: [PLUGIN.ID] }, + read: alertingFeatures, }, alert: { - read: { ruleTypeIds: ruleTypes, consumers: [PLUGIN.ID] }, + read: alertingFeatures, }, }, management: { 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 539f4cd77cc69..273c1c91dcc65 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 @@ -20,12 +20,12 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: {}, - read: {}, + all: [], + read: [], }, alert: { - all: {}, - read: {}, + all: [], + read: [], }, }, savedObject: { @@ -57,8 +57,8 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: {}, - read: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, + all: [], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, savedObject: { @@ -101,8 +101,8 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { alert: { - all: {}, - read: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, + all: [], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, savedObject: { @@ -140,12 +140,12 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: {}, - read: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, + all: [], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, alert: { - all: {}, - read: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, + all: [], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, savedObject: { @@ -192,8 +192,8 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, - read: {}, + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [], }, }, @@ -256,8 +256,8 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { alert: { - all: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, - read: {}, + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [], }, }, savedObject: { @@ -296,12 +296,12 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, - read: {}, + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [], }, alert: { - all: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, - read: {}, + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [], }, }, savedObject: { @@ -368,8 +368,8 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, - read: { ruleTypeIds: ['readonly-alert-type'], consumers: ['my-consumer'] }, + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], }, }, savedObject: { @@ -440,8 +440,8 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { alert: { - all: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, - read: { ruleTypeIds: ['readonly-alert-type'], consumers: ['my-consumer'] }, + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], }, }, @@ -485,12 +485,12 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: { ruleTypeIds: ['alert-type'], consumers: ['my-consumer'] }, - read: { ruleTypeIds: ['readonly-alert-type'], consumers: ['my-consumer'] }, + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], }, alert: { - all: { ruleTypeIds: ['another-alert-type'], consumers: ['my-consumer'] }, - read: { ruleTypeIds: ['readonly-alert-type'], consumers: ['my-consumer'] }, + all: [{ ruleTypeId: 'another-alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], }, }, 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 e40ba7038467a..bc6bde317db68 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 @@ -67,11 +67,10 @@ export class FeaturePrivilegeAlertingBuilder extends BaseFeaturePrivilegeBuilder ): string[] { const getAlertingPrivilege = ( operations: string[], - ruleTypeIds: readonly string[], - alertingEntity: string, - consumers: string[] + privileges: Array<{ ruleTypeId: string; consumers: string[] }>, + alertingEntity: string ) => - ruleTypeIds.flatMap((ruleTypeId) => + privileges.flatMap(({ ruleTypeId, consumers }) => consumers.flatMap((consumer) => operations.map((operation) => this.actions.alerting.get(ruleTypeId, consumer, alertingEntity, operation) @@ -80,14 +79,12 @@ export class FeaturePrivilegeAlertingBuilder extends BaseFeaturePrivilegeBuilder ); const getPrivilegesForEntity = (entity: AlertingEntity) => { - const allRuleTypeIds = get(privilegeDefinition.alerting, `${entity}.all.ruleTypeIds`) ?? []; - const allConsumers = get(privilegeDefinition.alerting, `${entity}.all.consumers`) ?? []; - const readRuleTypeId = get(privilegeDefinition.alerting, `${entity}.read.ruleTypeIds`) ?? []; - const readConsumers = get(privilegeDefinition.alerting, `${entity}.read.consumers`) ?? []; + const all = get(privilegeDefinition.alerting, `${entity}.all`) ?? []; + const read = get(privilegeDefinition.alerting, `${entity}.read`) ?? []; return uniq([ - ...getAlertingPrivilege(allOperations[entity], allRuleTypeIds, entity, allConsumers), - ...getAlertingPrivilege(readOperations[entity], readRuleTypeId, entity, readConsumers), + ...getAlertingPrivilege(allOperations[entity], all, entity), + ...getAlertingPrivilege(readOperations[entity], read, entity), ]); }; diff --git a/x-pack/plugins/stack_alerts/server/feature.ts b/x-pack/plugins/stack_alerts/server/feature.ts index ef91d5f3b6623..bacc0d2f3c951 100644 --- a/x-pack/plugins/stack_alerts/server/feature.ts +++ b/x-pack/plugins/stack_alerts/server/feature.ts @@ -16,6 +16,13 @@ import { GEO_CONTAINMENT_ID as GeoContainment } from './rule_types/geo_containme const TransformHealth = TRANSFORM_RULE_TYPE.TRANSFORM_HEALTH; +const alertingFeatures = [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth].map( + (ruleTypeId) => ({ + ruleTypeId, + consumers: [STACK_ALERTS_FEATURE_ID], + }) +); + export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { id: STACK_ALERTS_FEATURE_ID, name: i18n.translate('xpack.stackAlerts.featureRegistry.actionsFeatureName', { @@ -26,10 +33,7 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: { - ruleTypeIds: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth], - consumers: [STACK_ALERTS_FEATURE_ID], - }, + alerting: alertingFeatures, privileges: { all: { app: [], @@ -39,16 +43,10 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { }, alerting: { rule: { - all: { - ruleTypeIds: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth], - consumers: [STACK_ALERTS_FEATURE_ID], - }, + all: alertingFeatures, }, alert: { - all: { - ruleTypeIds: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth], - consumers: [STACK_ALERTS_FEATURE_ID], - }, + all: alertingFeatures, }, }, savedObject: { @@ -66,16 +64,10 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { }, alerting: { rule: { - read: { - ruleTypeIds: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth], - consumers: [STACK_ALERTS_FEATURE_ID], - }, + read: alertingFeatures, }, alert: { - read: { - ruleTypeIds: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth], - consumers: [STACK_ALERTS_FEATURE_ID], - }, + read: alertingFeatures, }, }, savedObject: {